一.setter/getter方法
objc_setAssociatedObject
objc_getAssociatedObject
在category(分類)中只是聲明屬性 ? 沒有實(shí)現(xiàn)setter/getter方法,并且直接重寫setter/getter方法也不能實(shí)現(xiàn),在編譯期不會(huì)報(bào)錯(cuò),但在運(yùn)行時(shí)會(huì)crash,
重寫setter/getter方法時(shí)需要用運(yùn)行時(shí)關(guān)聯(lián)屬性
@dynamic修飾的屬性不會(huì)自動(dòng)生成setter/getter/ivar ? 所以也需要自定義setter/getter方法
正確的重寫方法為 ? ? ?例:
const char *nameKey;
- (NSString *)setName:(NSString *)name {
//objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)
//<#id object#>要綁定的類 setter方法中直接就是 self
//<#const void *key#> key值 ? 不能重復(fù) ?如外邊聲明的nameKey
//<#id value#> 要綁定的數(shù)據(jù) 對象類型 基本數(shù)據(jù)類型要轉(zhuǎn)為NSNumber?如:name;
//<#objc_AssociationPolicy policy#> 內(nèi)存管理修飾符:retain/copy/assign
objc_setAssociatedObject(self, nameKey, name,OBJC_ASSOCIATION_COPY_NONATOMIC)
}
- (NSString *)name{
//objc_getAssociatedObject(<#id object#>, <#const void *key#>)
//<#id object#>要綁定的類 getter方法中直接就是 self
//<#const void *key#> key值 ? 不能重復(fù) ?如外邊聲明的nameKey
// ? 直接返回運(yùn)行時(shí)綁定的數(shù)據(jù) ?如果屬性為基本數(shù)據(jù)類型注意轉(zhuǎn)換類型
returnobjc_getAssociatedObject(self, nameKey)
}
二.查看更改類中的屬性 ?變量 ?協(xié)議 方法 等 ? 方法都是class開頭.
添加方法:
class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
//<#__unsafe_unretained Class cls#> 類 例:[Person class]
//<#SEL name#> ?方法選擇器
//<#IMP imp#> ? 方法實(shí)現(xiàn)的指針, 可用block實(shí)現(xiàn)創(chuàng)建imp_implementationWithBlock(<#block#>)
也可以找現(xiàn)有方法class_getMethodImplementation
//<#const char *types#> 方法返回類型 例 v@: 返回void 無參 ?i@:@ 返回int 有一個(gè)參
添加屬性:
objc_property_attribute_t type = {"T","NSUInterger"};
objc_property_attribute_t memory = {"R",""};
objc_property_attribute_t lock = {"N",""};
objc_property_attribute_t backName = {"V",[@"_age" UTF8String]};
objc_property_attribute_t attrs[] = {backName, memory, lock, type};
class_addProperty([Personclass],"age", attrs,4);
檢查屬性.成員變量.方法.協(xié)議等
unsignedintcount;
objc_property_t *property =class_copyPropertyList([Personclass], &count);
for(inti =0; i
objc_property_t pro = property[i];
constchar *name =property_getName(pro);
NSLog(@"%s",name);
}
方法(屬性...)交換,刪除,修改 獲取類信息等都可以在runtime 完成 ? 具體詳情后續(xù)在學(xué)習(xí).
三.unrecognized selector異常處理
這種異常是調(diào)用的方法沒有實(shí)現(xiàn)拋出的異常.Objective-C中方法調(diào)用的實(shí)質(zhì)是消息發(fā)送.如[objc method]的本質(zhì)是轉(zhuǎn)化為objc_msgSend(objc,@selected(method));選擇器開始在當(dāng)前實(shí)例對象的isa所指向的當(dāng)前類對象中找方法,當(dāng)前類對象存有對象方法列表,成員變量列表,屬性列表,并且有一個(gè)superClass指針指向父類,一個(gè)isa指針指向元對象,元類內(nèi)部存放的是類方法列表,元類的isa指針指向父元類,根元類的指針指向自己,根類對象(NSObject)的isa指針指向nil.
每個(gè) Objective-C 對象都有相同的結(jié)構(gòu)
方法調(diào)用時(shí) 先找當(dāng)前類對象內(nèi)的方法,如果沒有找父類的同名方法,依次向上查找,如果沒有找到就會(huì)拋出unrecognized selector異常,在runtime中給了三次機(jī)會(huì)作為彌補(bǔ)不會(huì)crash:
1.Method resolution
objc運(yùn)行時(shí)會(huì)調(diào)用+resolveInstanceMethod:或者+resolveClassMethod:般婆,讓你有機(jī)會(huì)提供一個(gè)函數(shù)實(shí)現(xiàn)叠洗。如果你添加了函數(shù),那運(yùn)行時(shí)系統(tǒng)就會(huì)重新啟動(dòng)一次消息發(fā)送的過程羞反,否則 妹田,運(yùn)行時(shí)就會(huì)移到下一步,消息轉(zhuǎn)發(fā)(Message Forwarding)空执。
id recoverMethodIMP(id self,SEL _cmd) {
NSLog(@"%s:動(dòng)態(tài)添加的方法",__FUNCTION__);
return@"1";
}
+ (BOOL)resolveClassMethod:(SEL)sel {
class_addMethod(self, sel, (IMP)recoverMethodIMP,"@:@");
return YES;
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
class_addMethod(self, sel, (IMP)recoverMethodIMP,"@:@");
returnYES;
}
2.Fast forwarding
如果目標(biāo)對象實(shí)現(xiàn)了-forwardingTargetForSelector:唬复,Runtime 這時(shí)就會(huì)調(diào)用這個(gè)方法,給你把這個(gè)消息轉(zhuǎn)發(fā)給其他對象的機(jī)會(huì)蔓倍。 只要這個(gè)方法返回的不是nil和self绍妨,整個(gè)消息發(fā)送的過程就會(huì)被重啟润脸,當(dāng)然發(fā)送的對象會(huì)變成你返回的那個(gè)對象。否則他去,就會(huì)繼續(xù)Normal Fowarding毙驯。
- ?(id)forwardingTargetForSelector:(SEL)aSelector{
return[ superforwardingTargetForSelector:aSelector];
}
3.如果上一步返回的對象未能完成消息發(fā)送的方法,它會(huì)發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil灾测,Runtime則會(huì)發(fā)出-doesNotRecognizeSelector:消息爆价,程序這時(shí)就掛了,如果返回了一個(gè)函數(shù)簽名,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation對象并發(fā)送-forwardInvocation:消息給目標(biāo)對象媳搪。
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
id sig = [super methodSignatureForSelector:aSelector];
sig = [NSMethodSignature signatureWithObjCTypes:"@@:"];
returnsig;
}
- (void)forwardInvocation:(NSInvocation*)anInvocation{
}