方法名:initialize
聲明
+ (void)initialize;
討論
在這個類或集成與這個類的子類第一次被加載前,runtime 會發(fā)送initialize消息來調(diào)用這個方法。initialize消息是這個類從runtime中收到的第一個消息,父類接收到這個消息在子類之前。
runtime是以線程安全方式向類發(fā)送initialize消息,而且對這個類發(fā)送的第一個消息就是initialize消息,其他的線程如果嘗試發(fā)送消息給這個類將會阻塞知道initialize完成。
如果子類沒有實現(xiàn)initialize,父類的initialize也許會多次被調(diào)用。runtime會根據(jù)繼承關(guān)系來調(diào)用或者子類明確的指出調(diào)用[super initialize]。如果你想自己去管理或者控制這種多次調(diào)用,你可以在下方注釋的地方進行實現(xiàn):
+ (void)initialize {
if (self == [ClassName self]) {
// ... do the initialization ...
}
}
因為initialize是以阻塞方式被調(diào)用的,所以在這個方法中應(yīng)盡可能減少代碼工作量,然后由于是阻塞方式調(diào)用所以任何調(diào)用其他類的代碼都可能導(dǎo)致死鎖。所以不要在initialize中進行復(fù)雜的邏輯,盡量簡化。
特別注意
initialize每個類只調(diào)用一次,如果你想對類和類的類別個字單獨進行初始化,你應(yīng)該實現(xiàn)load方法。
方法名:load
當(dāng)類或者類別被加入到runtime的時候進行調(diào)用,一般用于在類被加載前實現(xiàn)一些特殊的操作
聲明
+ (void)load;
討論
load消息在動態(tài)加載和靜態(tài)鏈接的時候都會被發(fā)送,但僅僅這個類或者類別實現(xiàn)這個方法的時候才會有相應(yīng)
初始化順序如下:
- 調(diào)用所有的Framework中的初始化方法
- 調(diào)用所有的
+load方法 - 調(diào)用C++的靜態(tài)初始化方法及C/C++中的attribute(constructor)函數(shù)
- 調(diào)用所有鏈接到目標(biāo)文件的framework中的初始化方法
此外:
- 一個類的+load方法在其父類的+load方法后調(diào)用
- 一個Category的
+load方法在被其擴展的類的自有+load方法后調(diào)用
在+load方法中,可以安全地向其它無關(guān)的類發(fā)送消息,但接收消息的類中的+load方法可能尚未實現(xiàn)。
方法名:init
子類用來初始化一個新的對象,并立刻給該對象分配內(nèi)存
聲明
- (instancetype)init;
返回值
一個初始化的對象,如果因為某種原因沒有創(chuàng)建成果那么就會返回nil,這樣就不會拋出異常。
討論
一個init消息一定會與alloc(或者allocWithZone:)消息出現(xiàn)在同一行代碼中:
SomeClass *object = [[SomeClass alloc] init];
一個對象只有被初始化了才能被使用。
在一般情況下,你必須調(diào)用父類初始化方法來初始化并返回一個對象,如果不能初始化的話,就會返回nil。舉例,假設(shè)有一個類——BuiltInCamera類,這個類當(dāng)運行的設(shè)備中沒有攝像頭的時候進行初始化會返回nil
- (instancetype)init {
if (self = [super init]) {
// Initialize self
}
return self;
}
在一般情況下,你都要通過init來獲取返回對象,而不是通過alloc或者allocWithZone:。
initialize,load,init 代碼示例
創(chuàng)建一個person類,并在其.m文件中實現(xiàn)以下三個方法
//
// Person.m
// AFNetworingSourceTest
//
// Created by Mac on 2018/7/12.
// Copyright ? 2018年 MJJ. All rights reserved.
//
#import "Person.h"
@implementation Person
+(void)initialize {
NSLog(@"%s", __FUNCTION__);
}
-(instancetype)init {
NSLog(@"%s", __FUNCTION__);
return self;
}
+(void)load {
NSLog(@"%s", __FUNCTION__);
}
@end
然后在viewDidLoad中初始化兩個實例
- (void)viewDidLoad {
[super viewDidLoad];
Person* person1 = [[Person alloc]init];
Person* person2 = [[Person alloc]init];
// Do any additional setup after loading the view, typically from a nib.
}
控制臺打印:
2018-07-12 12:34:19.095313+0800 AFNetworingSourceTest[62407:43110238] +[Person load]
2018-07-12 12:15:31.053588+0800 AFNetworingSourceTest[61566:43077247] +[Person initialize]
2018-07-12 12:15:31.053690+0800 AFNetworingSourceTest[61566:43077247] -[Person init]
2018-07-12 12:15:31.053787+0800 AFNetworingSourceTest[61566:43077247] -[Person init]
可以看到盡管創(chuàng)建了2個實例,但是initialize只調(diào)用了一次,而且是在創(chuàng)建的時候被調(diào)用,然后init調(diào)用了兩次
接下來給Person創(chuàng)建一個子類Man
#import "Person.h"
@interface Man : Person
@end
#import "Man.h"
@implementation Man
@end
修改Person的initialize方法打印類名
+(void)initialize {
NSLog(@"%s %@", __FUNCTION__,[self class]);
}
控制臺打印:
2018-07-12 12:31:47.690548+0800 AFNetworingSourceTest[62342:43103509] +[Person load]
2018-07-12 12:31:49.123319+0800 AFNetworingSourceTest[62342:43103509] +[Person initialize] Person
2018-07-12 12:31:49.123443+0800 AFNetworingSourceTest[62342:43103509] -[Person init]
2018-07-12 12:31:49.123572+0800 AFNetworingSourceTest[62342:43103509] -[Person init]
2018-07-12 12:31:49.123665+0800 AFNetworingSourceTest[62342:43103509] +[Person initialize] Man
2018-07-12 12:31:49.123740+0800 AFNetworingSourceTest[62342:43103509] -[Person init]
initialize方法輸出了兩次,一個子類沒有實現(xiàn)initialize方法,那么父類會調(diào)用這個方法兩次,一次為自己,另一次為子類。load方法在initialize之前調(diào)用
方法名:alloc
給對應(yīng)的類返回一個新的實例
聲明
+ (instancetype)alloc;
返回值
一個新的實例
討論
這個新的實例的isa指針被初始化為一個數(shù)據(jù)結(jié)構(gòu)體用來描述該類;其他實例變量的內(nèi)存被設(shè)置為0.
你必須使用init方法來完成初始化過程。
舉例:
TheClass *newObject = [[TheClass alloc] init];
初始化不要重寫alloc,而應(yīng)該根據(jù)每個類來實現(xiàn)其自身的init方法。
因為歷史原因,alloc會喚起allocWithZone:方法
方法名:allocWithZone
給對應(yīng)的類返回一個新的實例
聲明
+ (instancetype)allocWithZone:(struct _NSZone *)zone;
參數(shù)
zone 這個參數(shù)已被忽略,傳nil即可
返回值
一個新的實例
討論
這個新的實例的isa指針被初始化為一個數(shù)據(jù)結(jié)構(gòu)體用來描述該類;其他實例變量的內(nèi)存被設(shè)置為0.
你必須使用init方法來完成初始化過程。
舉例:
TheClass *newObject = [[TheClass allocWithZone:nil] init];
初始化不要重寫alloc,而應(yīng)該根據(jù)每個類來實現(xiàn)其自身的init方法。
這個方法沒用了,沒啥好看的
方法名:copy
返回一個從從copyWithZone:獲取的對象
聲明
- (id)copy;
返回值
返回的對象是從NSCopying協(xié)議的copyWithZone:方法中獲取
討論
使用NSCoping協(xié)議可以很方便的為一個類添加copy方法,當(dāng)然,一定要實現(xiàn)copyWithZone:方法,不然會拋出一個異常。
繼承于NSObject的類自身不提供NSCopying協(xié)議,子類必須對這個協(xié)議添加支持,并且實現(xiàn)copyWithZone:方法
子類的copyWithZone:調(diào)用順序:這個方法會首先向父類發(fā)送消息,并將其實現(xiàn),除非這個子類是直接從NSObject派生
方法名:copyWithZone
返回一個接收者(對象)
聲明
+ (id)copyWithZone:(struct _NSZone *)zone;
參數(shù)
zone
不用管這個參數(shù),直接可以忽略
返回值
一個對象
討論
當(dāng)你需要一個可以實現(xiàn)NSCopying協(xié)議的類時需要用到這個方法,要實現(xiàn)這個方法.例如,該方法允許您使用類對象作為NSDictionary對象的鍵,不用重寫這個方法
方法名:mutableCopy
從mutableCopyWithZone 返回一個對象,zone參數(shù)為nil
聲明
- (id)mutableCopy;
返回值
返回的對象是由NSMutableCopying協(xié)議方法mutableCopyWithZone:返回,zone參數(shù)為nil
討論
對于采用NSMutableCopying協(xié)議的類來說,這是一種方便的方法。如果mutableCopyWithZone沒有實現(xiàn),則會引發(fā)異常。
方法名:mutableCopyWithZone:
返回一個對象
聲明
zone:用于創(chuàng)建內(nèi)存區(qū)域
討論
類對象可以使用這個方法來使自身符合NSMutableCopying協(xié)議,例如,該方法允許您使用類對象作為NSDictionary對象的鍵,不用重寫這個方法
方法名:dealloc
釋放對象占用的內(nèi)存
聲明
- (void)dealloc;
討論
如果在該對象內(nèi)存被釋放時候再次發(fā)送消息給該對象就會生成一個錯誤,可以重寫這個方法來釋放實例變量之外的對象的內(nèi)存釋放,例:
- (void)dealloc {
free(myBigBlockOfMemory);
}
在delloc的實現(xiàn)中,不要調(diào)用超類的實現(xiàn)。你應(yīng)該盡量避勉使用 dealloc 管理有限資源諸如文件描述符的生命周期。決不要直接發(fā)送 dealloc 消息。相反,任何對象的 dealloc 方法由運行時調(diào)用。參看 高級內(nèi)存管理編程指南 以獲得更詳細的內(nèi)容。
特別注意事項
當(dāng)未使用 ARC 時,你的 dealloc 實現(xiàn)必須把調(diào)用父類的實現(xiàn)作為最后一條指令。(隱含的意思就是,使用 ARC 時不能調(diào)用父類的實現(xiàn))
方法名:new
分配給接收類一個新實例,向它發(fā)送一個init消息,并返回初始化的對象。
聲明
+ (instancetype)new;
返回值
一個接收類的新的實例
討論
該方法是alloc和init的組合。與alloc一樣,它初始化新對象的isa實例變量,以便指向類數(shù)據(jù)結(jié)構(gòu)。然后調(diào)用init方法來完成初始化過程。
方法名:class
返回一個類對象
聲明
+ (Class)class;
返回值
一個類對象
討論
當(dāng)一個類是消息接受者是可以通過它的名稱來引用它。在其他所有情況下,類對象必須通過此方法或者類似方法獲得。例如,這里將SomeClass作為一個參數(shù)餐遞給isKindOfClass:方法(在NSObject協(xié)議中聲明):
BOOL test = [self isKindOfClass:[SomeClass class]];