在OC 中,使用category會讓我們在開發(fā)中非常方便,可以為某個類增添方法,對類別自己有一點小小的體會,首先先來介紹一下類別
類別是在運行時決定的,在運運行時才會分配相應的內(nèi)存空間,在就決定了在編譯期是不能給某個類增加屬性,否則會影響內(nèi)存布局,從而導致crash ,若想給某個類增加一個屬性,需要在運行時添加,首先先介紹下類別的結構
typedef struct category_t {
? ?const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
} category_t;
這個結構體理念包含這個類別的名字,實例方法,類方法,協(xié)議名,和實例屬性
正如我們所知的那樣,當我們重寫類的一個方法以后,會覆蓋原來類的方法,它為什么會覆蓋原來類的方法呢,我們先來看一下當調(diào)用一個方法的時候是怎么運行的
BOOL classExists = NO;
? ? ? ? ? ?if (cat->instanceMethods || ?cat->protocols
|| ?cat->instanceProperties)
{
addUnattachedCategoryForClass(cat, cls, hi);
if (isRealized(cls)) {
remethodizeClass(cls);
classExists = YES;
}
if (PrintConnecting) {
_objc_inform("CLASS: found category -%s(%s) %s",
getName(cls), cat->name,
classExists ? "on existing class" : "");
}
}
if (cat->classMethods ?|| ?cat->protocols
/* || ?cat->classProperties */)
{
addUnattachedCategoryForClass(cat, cls->isa, hi);//關聯(lián)映射
if (isRealized(cls->isa)) {
remethodizeClass(cls->isa);//添加事件
}
if (PrintConnecting) {
_objc_inform("CLASS: found category +%s(%s)",
getName(cls), cat->name);
}
} ?
在這里面我們可以看到,是先根據(jù)isa 指針找到該類,然后在該類的方法列表里面找到該方法的實現(xiàn),當重寫一個類的方法后,它會將重寫的方法,放在方法列表的第一位,當?shù)谝淮握业皆摲椒ǖ臅r候就不會在查找,就會執(zhí)行重寫的方法實現(xiàn),如果我們想執(zhí)行原來的方法實現(xiàn)就可以跳過方法列表前面的方法實現(xiàn),執(zhí)行最后一個該方法的實現(xiàn)就可以了
Class currentClass = [MyClass class];
MyClass *my = [[MyClass alloc] init];
if (currentClass) {
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
IMP lastImp = NULL;
SEL lastSel = NULL;
for (NSInteger i = 0; i < methodCount; i++) {
Method method = methodList[i];
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))
encoding:NSUTF8StringEncoding];
if ([@"printName" isEqualToString:methodName]) {
lastImp = method_getImplementation(method);
lastSel = method_getName(method);
}
}
typedef void (*fn)(id,SEL);
if (lastImp != NULL) {
fn f = (fn)lastImp;
f(my,lastSel);
}
free(methodList);
}
上面的printName為重寫的方法名,獲取最后一個類名和方法實現(xiàn),這樣就可以調(diào)用被重寫的方法實現(xiàn)。
前面提到不可以在編譯期給類增加屬性,那可以在運行期動態(tài)的給某個類添加屬性,可以調(diào)用message API來實現(xiàn)
+ (void)load
{
NSLog(@"%@",@"load in Category1");
}
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self,
"name",
name,
OBJC_ASSOCIATION_COPY);
}
- (NSString*)name
{
NSString *nameObject = objc_getAssociatedObject(self, "name");
return nameObject;
}
我們對某個類得分類中增加一個name 屬性,重寫name 的set 和get方法就可以為其添加屬性了,此外給大家奉上我做的一個相關的demo 地址類別的方法覆蓋和添加屬性此外在此謝謝美團技術團隊的技術分享美團類別分享