在說分類之前我們先來認(rèn)識兩個概念:property(屬性) Ivar(成員變量)
在xcode中我們用@property關(guān)鍵字生個的對象就是一個屬性 為這個屬性添加_它就是成員變量,例如:
@property (nonatomic,copy)NSString *height;
height
現(xiàn)在就是一個屬性 _height
就是一個成員變量歧匈。當(dāng)我們用@property聲明了一個屬性后xcode會自動幫我們生成成員變量和set,get方法涂身,所以弱化了我們對這一塊的認(rèn)知容易造成兩個概念的混淆。
弄清概念后我們就來談?wù)劽嬖囍薪?jīng)常被問到Cagetory為什么不能添加屬性
這個問題罩句。
對于了解Cagetory原理的大神來說當(dāng)聽到面試官這個問題柒室,你完全可以懟回去,記住你要狠狠的懟他,因為他什么都不懂居然敢來問你這個問題凯肋。沒有殺害就沒有買賣,沒有面試就沒有傷害我們通過例子的對比看看這個面試題問題出在哪里汽馋。
首先我們創(chuàng)建一個類
@interface Student : NSObject
@property (copy , nonatomic) NSString *name;
@end
然后我們通過runtime打印出它的屬性和成員變量侮东,方法
#import "Student.h"
#import <objc/runtime.h>
@implementation Student
+ (void)load{
// 打印屬性
unsigned int outCount = 0;
objc_property_t *property_t = class_copyPropertyList([Student class], &outCount);
for (int i=0; i<outCount; i++) {
objc_property_t property = property_t[i];
const char *name = property_getName(property);
NSLog(@"property %s",name);
}
// 打印成員變量
unsigned int outCount2 = 0;
Ivar *var = class_copyIvarList([Student class], &outCount2);
for (int i=0; i<outCount2; i++) {
Ivar ivar = var[i];
const char *name = ivar_getName(ivar);
NSLog(@"ivar %s",name);
}
// 打印方法
unsigned int outCount3 = 0;
Method *method = class_copyMethodList([Student class], &outCount3);
for (int i =0; i<outCount3; i++) {
Method meth = method[i];
SEL sel = method_getName(meth);
NSLog(@"Sel %@",NSStringFromSelector(sel));
}
}
@end
log:
2017-11-06 17:14:32.879747+0800 Demo2[2281:213110] property name
2017-11-06 17:14:32.880340+0800 Demo2[2281:213110] ivar _name
2017-11-06 17:14:32.880825+0800 Demo2[2281:213110] Sel .cxx_destruct
2017-11-06 17:14:32.880990+0800 Demo2[2281:213110] Sel name
2017-11-06 17:14:32.881178+0800 Demo2[2281:213110] Sel setName:
通過Log可以看到在一個正常類中聲明一個屬性系統(tǒng)會自動的幫我們生成成員變量和get,set方法。
我們再創(chuàng)建一個分類
@interface Student (Cagetory)
@property (nonatomic,copy)NSString *age;
@end
log:
2017-11-06 17:23:45.765658+0800 Demo2[2394:219523] property age
2017-11-06 17:23:45.766444+0800 Demo2[2394:219523] property name
2017-11-06 17:23:45.766794+0800 Demo2[2394:219523] ivar _name
2017-11-06 17:23:45.767261+0800 Demo2[2394:219523] Sel .cxx_destruct
2017-11-06 17:23:45.767709+0800 Demo2[2394:219523] Sel name
2017-11-06 17:23:45.767926+0800 Demo2[2394:219523] Sel setName:
對比兩次打印結(jié)果發(fā)現(xiàn)當(dāng)給Student添加一個屬性后豹芯,再打印Student的屬性悄雅,成員變量,方法會發(fā)現(xiàn)多了一個age
屬性但是沒有age對應(yīng)的_age和set铁蹈,get方法宽闲。到此我們就揪出了剛剛的面試題題目本身問題出在哪里。你可以告訴面試官分類是可以添加屬性的木缝,只是系統(tǒng)不會幫我們自動生成對應(yīng)的成員變量和方法便锨。
我們給分類添加了一個屬性但是系統(tǒng)沒有幫我們生成成員變量和set,get方法那對分類有什么影響呢?我們再來看一個例子:
#import "Student+Cagetory.h"
@implementation Student (Cagetory)
@dynamic age;
- (void)setAge:(NSString *)age
{
//_age = age 是通過成員變量給屬性age復(fù)制我碟,為什么這里不能用self.age = age
// 因為當(dāng)你調(diào)用self.x = 系統(tǒng)默認(rèn)你在調(diào)用x的set方法放案,你在set方法里面調(diào)用set方法這肯定是有問題的
// _age = age; 你會發(fā)現(xiàn)找不到_age對象
// 程序會crash
self.age = age;
}
- (NSString *)age{
// return _age; 同理你會發(fā)現(xiàn)找不到_age對象
// 同理程序會crash
return self.age;
}
@end
當(dāng)我們手動實現(xiàn)age的set get方法你會發(fā)現(xiàn)在取值和賦值的時候找不到_age對象,無法進(jìn)行賦值和取值操作矫俺,如果強(qiáng)行調(diào)用set.x程序會crash吱殉。如果我們手動實現(xiàn)age屬性的成員變量_age會怎么樣:
你會發(fā)現(xiàn)在分類中系統(tǒng)提示不允許實現(xiàn)屬性的成員變量掸冤,至于為什么不讓給分類添加成員變量這要從系統(tǒng)對分類的定義來分析。
Category 在 runtime 中是用一個結(jié)構(gòu)體表示的:
struct _category_t {
const char *name;
struct _class *cls;
const struct _method_list_t *instance_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
}
從分類的定義中我們看到它包括了分類的名字友雳,所屬類稿湿,成員方法列表,協(xié)議列表押赊,屬性列表饺藤,但并沒有定義Ivar列表。既然沒有Ivar列表那自然就無法正常的生成成員變量和對方的方法流礁。
從另一個層面講分類本身并不是真正意義上的類涕俗。它是runtime在動態(tài)允許時為它所屬的類添加了一些成員方法而已。
如果在項目中遇到變態(tài)需求神帅,非要給分類添加成員變量怎么變再姑,那就要用到runtime技巧。以剛才的Student例子為例:
static const NSString *key = @"ageKey";
- (void)setAge:(NSString *)age
{
objc_setAssociatedObject(self, &key, age, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)age{
return objc_getAssociatedObject(self, &key);
}
只需要導(dǎo)入runtime 然后定義一個靜態(tài)不可變字符串找御,在set和get方法里面關(guān)聯(lián)綁定就可以了元镀。
參考
https://juejin.im/entry/5a02aa546fb9a045204ba5fa?utm_medium=ios&utm_source=weixinqun
http://blog.csdn.net/lizitao/article/details/77196620
美團(tuán)團(tuán)隊博客
https://tech.meituan.com/DiveIntoCategory.html