分類不能自動建立 get set 方法
阿新 • • 發佈:2018-12-23
前幾天有人問我一個問題:為什麼分類不能自動建立get set方法。老實說,筆者從來沒有去思考過這個問題。於是這次通過程式碼實踐跟runtime
原始碼來探究這個問題。
準備工作
為了能減少輸出類資料的程式碼工作,筆者基於NSObject
的分類封裝了一套程式碼
其中輸出類例項變數的具體程式碼:
Objective-C1234567891011121314151617 | -(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 |
+(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]));}}
執行結果:屬性name
和age
生成了對應的_propertyName
的例項變數以及setter
和getter
- 動態生成屬性
age
Objective-C1234 @implementationPerson<ahref='http://www.jobbole.com/members/Dynamic2016'>@dynamic</a>age;@end
執行結果:缺少了_age
變數以及對應的setAge:
和age
方法 - 手動實現
setter/getter
Objective-C1234567 @implemetation Person<ahref='http://www.jobbole.com/members/Dynamic2016'>@dynamic</a>age;-(void)setAge:(NSUInteger)age{}-(NSUInteger)age{return18;}@end
輸出結果:未生成_age
例項變數 - 手動實現
_pId
的setter/getter
Objective-C123456789101112 @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
無異
通過上面的幾段試驗,可以得出@property
的公式:
分類屬性
- 分類中新增
weigh
和height
屬性
123456 @interfacePerson(category)@property(nonatomic,assign)CGFloat weigh;@property(nonatomic,assign)CGFloat height;@end
執行結果:weigh
和height
未生成例項變數以及對應的setter/getter
,與@dynamic
修飾的age
表現一致 - 使用
@synthesize
自動合成setter/getter
方法時編譯報錯 - 手動實現
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
沒有發生任何變化
通過程式碼實驗,可以得出下面兩個結論:
- 分類屬性相當於
- 缺少
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] |