對(duì)象在運(yùn)行時(shí)獲取其類(lèi)型的能力稱為內(nèi)省。內(nèi)省可以有多種方法實(shí)現(xiàn)。
OC運(yùn)行時(shí)內(nèi)省的4個(gè)方法:
判斷對(duì)象類(lèi)型:
-(BOOL) isKindOfClass: 判斷是否是這個(gè)類(lèi)或者這個(gè)類(lèi)的子類(lèi)的實(shí)例
-(BOOL) isMemberOfClass: 判斷是否是這個(gè)類(lèi)的實(shí)例
判斷對(duì)象or類(lèi)是否有這個(gè)方法
-(BOOL) respondsToSelector: 判讀實(shí)例是否有這樣方法
+(BOOL) instancesRespondToSelector: 判斷類(lèi)是否有這個(gè)方法
在 Objective-C 中,id類(lèi)型類(lèi)似于(void*) ,可以指向任何類(lèi)的對(duì)象,但在運(yùn)行時(shí)對(duì)象的類(lèi)型不再是id,而是該對(duì)象真正所屬的類(lèi)。
Person *person = [[Person alloc] init];
NSArray *arr = @[person];
id obj = arr[0]; //OC集合中取出的對(duì)象都是id類(lèi)型
此時(shí)可通過(guò)
BOOL isPersonClass = [obj isKindOfClass: [Person class] ];
來(lái)判斷obj是否Person類(lèi)型或其子類(lèi)的對(duì)象。
在 Objective-C 中,用父類(lèi)類(lèi)型定義的指針,可以指向其子類(lèi)的對(duì)象,但在運(yùn)行時(shí)對(duì)象真實(shí)類(lèi)型會(huì)是子類(lèi)。
//例如 Boy是Person的子類(lèi),現(xiàn)定義:
Person *p = [[Boy alloc] init];
可通過(guò) BOOL isBoy = [p isMemberOfClass: [Boy class] ];
判斷Person *類(lèi)型的p是否是Boy類(lèi)型。
在使用代理調(diào)用代理方法時(shí),并不知道代理對(duì)象有沒(méi)有實(shí)現(xiàn)對(duì)應(yīng)方法,如未實(shí)現(xiàn)就會(huì)報(bào)方法找不到的錯(cuò)誤。此時(shí)最好使用respondsToSelector:先判斷下,然后調(diào)用會(huì)比較安全。
另外,可以用來(lái)判斷方法的版本,避免找不到方法報(bào)錯(cuò)。
例如:iOS8以后UIApplication新增注冊(cè)遠(yuǎn)程通知的方法,如果ios7及以下系統(tǒng)中調(diào)用[application registerForRemoteNotifications];立即會(huì)崩潰。
@interface UIApplication (UIRemoteNotifications)
- (void)registerForRemoteNotifications NS_AVAILABLE_IOS(8_0);
@end
此時(shí)可以用respondsToSelector來(lái)判斷:
if ([application respondsToSelector:@selector(registeredForRemoteNotifications)])
{ //IOS8
[application registerForRemoteNotifications];
}
else { // ios7
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
//夾在3個(gè)#pragma中間的不報(bào)方法過(guò)期警告
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
#pragma clang diagnostic pop
}
/*
如果不知道某個(gè)方法在哪個(gè)版本出現(xiàn)的,就可以用respondsToSelector來(lái)判斷以避免崩潰。
當(dāng)然也可以先判斷[UIDevice currentDevice].systemVersion.floatValue >= 8.0,
再調(diào)用registerForRemoteNotifications方法。
*/