1. 程式人生 > >分類不能自動建立 get set 方法

分類不能自動建立 get set 方法

前幾天有人問我一個問題:為什麼分類不能自動建立get set方法。老實說,筆者從來沒有去思考過這個問題。於是這次通過程式碼實踐跟runtime原始碼來探究這個問題。

準備工作

為了能減少輸出類資料的程式碼工作,筆者基於NSObject的分類封裝了一套程式碼

 11783864-c416370fe938ea40

其中輸出類例項變數的具體程式碼:

Objective-C
1234567891011121314151617 -(void)logIvarsWithExpReg:(NSString*)expReg customed:(BOOL)customed{[NSObjectkRecordOBJ];unsignedintivarCount;Ivar*ivars=class_copyIvarList([selfclass],&ivarCount);for(intidx=0;idx<ivarCount;idx++){Ivarivar=ivars[idx];NSString
*ivarName=[NSString stringWithUTF8String: ivar_getName(ivar)];if(customed&&[kOBJIvarNames containsObject: ivarName]){continue;}if(expReg&&!kValidExpReg(ivarName,expReg)){continue;}printf("ivar: %s --- %s\n",NSStringFromClass([selfclass]).UTF8String,ivarName.UTF8String);}free(ivars);}

+(void)kRecordOBJ採用dispatch_once的方式將NSObject存在的資料儲存到三個陣列中,用來排除父類的資料輸出

類的屬性

  • 正常建立類
    123456789101112131415161718 @interfacePerson:NSObject{int_pId;}@property(nonatomic,copy)NSString *name;@property(nonatomic,assign)NSUInteger age;@endintmain(intargc,char*argv[]){@autoreleasepool{Person *p=[[Person alloc]init];[plogCustomIvars];[plogCustomMethods];[plogCustomProperties];returnUIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate class]));}}

    執行結果:屬性nameage生成了對應的_propertyName的例項變數以及settergetter  12783864-eae915b82abc97ca
  • 動態生成屬性age
    Objective-C
    1234 @implementationPerson<ahref='http://www.jobbole.com/members/Dynamic2016'>@dynamic</a>age;@end

    執行結果:缺少了_age變數以及對應的setAge:age方法  13783864-63584be595c2c024
  • 手動實現setter/getter
    Objective-C
    1234567 @implemetation Person<ahref='http://www.jobbole.com/members/Dynamic2016'>@dynamic</a>age;-(void)setAge:(NSUInteger)age{}-(NSUInteger)age{return18;}@end

    輸出結果:未生成_age例項變數  14783864-b81880b32b2e6dba
  • 手動實現_pIdsetter/getter
    Objective-C
    123456789101112 @implemetation Person<ahref='http://www.jobbole.com/members/Dynamic2016'>@dynamic</a>age;-(void)setAge:(NSUInteger)age{}-(NSUInteger)age{return18;}-(void)setPId:(int)pId{_pId=pId;}-(int)pId{return_pId;}@end[p setValueForKey:@"pId"];

    執行結果:KVC的訪問會觸發setter方法,_pId除了無法通過點語法訪問外,其他表現與@property無異  15783864-4b6419ceb5605328

通過上面的幾段試驗,可以得出@property的公式:

 16783864-a859e0163a20a5b7

分類屬性

  • 分類中新增weighheight屬性
    123456 @interfacePerson(category)@property(nonatomic,assign)CGFloat weigh;@property(nonatomic,assign)CGFloat height;@end

    執行結果:weighheight未生成例項變數以及對應的setter/getter,與@dynamic修飾的age表現一致  17783864-7fabb41cc79e1d02
  • 使用@synthesize自動合成setter/getter方法時編譯報錯  18783864-094fbbf37d5136e1
  • 手動實現setter/getter
    @implemetation Person (category)
    1234 -(void)setWeigh:(CGFloat)weigh{}-(CGFloat)weigh{return150;}@end

    執行結果:與後重寫其setter/getter表現一致
  • 動態繫結屬性來實現setter/getter
    1234567891011121314151617181920212223242526 void*kHeightKey=&kHeightKey;@implemetation Person(category)-(void)setWeigh:(CGFloat)weigh{}-(CGFloat)weigh{return150;}-(void)setHeight:(CGFloat)height{objc_setAssociatedObject(self,kHeightKey,@(height),OBJC_ASSOCIATION_RETAIN_NONATOMIC);}-(CGFloat)height{returnreturn[objc_getAssociatedObject(self,kHeightKey)doubleValue];;}@end[plogCustomIvars][plogCustomMethods];[plogCustomProperties];CGFloat height=180;p.height=180;height=p.height;[plogCustomIvars][plogCustomMethods];[plogCustomProperties];

    執行結果:動態繫結前後ivar沒有發生任何變化  19783864-5ead3ca71e138237

通過程式碼實驗,可以得出下面兩個結論:

  • 分類屬性相當於
  • 缺少ivar的情況下無法使用@synthesize自動合成屬性

以及一個猜想:

  • 在類完成載入後無法繼續新增ivar

通過runtime動態建立類驗證猜想:

1234567891011121314151617181920212223242526272829303132 intmain(intargc,char*argv[]){NSString *className=@"Custom";ClasscustomClass=objc_allocateClassPair([NSObject class],className.UTF8String,0);class_addIvar(customClass,@"ivar1".UTF8String,sizeof(NSString *),0,"@");objc_property_attribute_t type1={"T","@\"NSString\""};objc_property_attribute_t ownership1={"C","N"};objc_property_attribute_t atts1[]={type1,ownership1};class_addProperty(customClass,"property1",atts1,2);objc_registerClassPair(customClass);id instance=[[customClass alloc]init];NSLog(@"\nLog Ivars ===================");[instance logCustomIvars];NSLog(@"\nLog methods ===================");[instance logCustomMethods];NSLog(@"\nLog properties ===================");[instance logCustomProperties];class_addIvar(customClass,@"ivar2".UTF8String,sizeof(NSString *),0,"@");objc_property_attribute_t type2={"T","@\"NSString\""};objc_property_attribute_t ownership2={"C","N"};objc_property_attribute_t atts2[]={type2,ownership2};class_addProperty(customClass,"property2",atts2,2);instance=[[customClass alloc]init];NSLog(@"\nLog Ivars ===================");[instance logCustomIvars];NSLog(@"\nLog methods ===================");[instance logCustomMethods]