關於iOS Class Category的整理
參考
作用
- 把一個類中的方法實現分成幾個檔案,這樣做的好處:
a)可以減小單個檔案的體積。
b)把不同功能的方法,分類在不同的檔案中。
c)可由不同的開發者負責不同的分類。
d)按需載入不同的分類。 - 宣告私有方法(建立私有方法的前向引用)。
分類中的非私有方法,也是屬於原來那個類的方法,呼叫的時候,也是用原來的類去呼叫,而不是新的其它的類。
例如:Person
@interface Person : NSObject
@property(retain,nonatomic)NSString* name;
-(void)printName;
@end
@implementation Person
-(void)printName{
NSLog(@"%@",self.name);
}
@end
以及它的分類Person+Skill
@interface Person (Skill)
-(void)eatSkill;
@end
@implementation Person (Skill)
-(void)eatSkill{
NSLog(@"人的技能之一:吃飯");
}
@end
那麼呼叫分類的方法,其實就是Person
呼叫自己的方法一樣:
#import "Person.h"
#import "Person+Skill.h"
Person *person = [Person alloc]init];
person.name = @"wxx";
[person printName];
[person eatSkill];
宣告私有方法(建立私有方法的前向引用)
我們都知道,在Objective-C
中,建立一個方法,如果在.h檔案中宣告瞭(.m中實現),那麼這個方法屬於公有方法,也就是public。如果只是在Extension
(類擴充套件)中宣告(關於Extension點這裡),或者不宣告,那麼就是屬於私有方法,也就是private。在Extension
中宣告方法如下:
@interface Person(){
}
-(void)privateMothod;
@end
預設情況下,私有方法是不能在其他類中使用的,強制使用,Xcode編譯器會報錯。如果非要訪問私有方法,可以新建該方法所屬類的分類,在分類的.h中宣告該方法,.m中不用實現。嚴格意義上來說,Objective-C中,是沒有私有方法的。後面會說到為什麼
下面是一個例子:
在類中建立一個私有方法,擴充套件類可宣告可不宣告
#import "Person.h"
@interface Person(){
}
-(void)privateMethod;
@end
@implementation Person
-(void)privateMethod{
NSLog(@"this is class private method");
}
@end
分類中.h宣告該私有方法:
#import "Person.h"
@interface Person (PrivateMethod)
//只宣告,不實現
-(void)privateMethod;
@end
#import "Person+PrivateMethod.h"
@implementation Person (PrivateMethod)
@end
最終執行:
#import "Person.h"
#import "Person+PrivateMethod.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc]init];
[person privateMethod];
}
@end
執行結果:
this is class private method
通過上面的方法,實現了呼叫類中的私有方法,由此得到以下結論
Objective-C中,是沒有私有方法的
Q:為什麼說Objective-C中,是沒有私有方法的?
A:因為通過執行時,我們可以獲取到一個類中的所有方法名;而有了方法名,可以如上新增分類的方式,呼叫私有方法!Q:如何獲取一個類中的所有方法名?
A:如下所示:
unsigned int count;
Method *methods = class_copyMethodList([Person class], &count);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL selector = method_getName(method)
NSString *name = NSStringFromSelector(selector);
NSLog(@"%@",name);
}
列印結果:
2017-12-11 17:19:41.386635+0800 WxxDemo[2068:829821] eatSkill
2017-12-11 17:19:41.386780+0800 WxxDemo[2068:829821] haha
2017-12-11 17:19:41.386912+0800 WxxDemo[2068:829821] setHaha:
2017-12-11 17:19:41.387020+0800 WxxDemo[2068:829821] printName
2017-12-11 17:19:41.387116+0800 WxxDemo[2068:829821] privateMethod
2017-12-11 17:19:41.387252+0800 WxxDemo[2068:829821] .cxx_destruct
2017-12-11 17:19:41.387404+0800 WxxDemo[2068:829821] name
2017-12-11 17:19:41.387495+0800 WxxDemo[2068:829821] setName:
可以看到,私有方法名稱(例如:privateMethod),是可以獲取到的!如何呼叫私有方法,相信大家已經很清楚。
分類中新增屬性
直接在分類.h中新增屬性(嚴格意義上來講,不是新增,而是宣告。):
@interface Person (Skill)
@property (nonatomic,copy)NSString *haha;
@end
在分類的.m檔案中,就會出現如下的警告:
以上警告,告訴我們:需要手動新增方法,或者使用@dynamic在執行時動態實現關聯屬性
如果沒有按照警告的做法來實現,直接呼叫該屬性:
person.haha = @"哈哈";
就會報出如下的crach,果然上面的警告不能忽略啊:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person setHaha:]: unrecognized selector sent to instance 0x60000001f7a0'
@property分析
@interface Person : NSObject
@property (nonatomic,copy)NSString *haha;
@end
實際上,@property可以看成是Objective-C 程式設計中的“巨集”,它有超程式設計的思想。上面這段程式碼,實際上會做三件事:
- 生成例項變數 _haha
- 生成 getter 方法 - haha
- 生成 setter 方法 - setHaha:
@implementation DKObject {
NSString * _haha;
}
- (NSString *) haha {
return _haha;
}
- (void)setHaha:(NSString *) haha {
_haha = haha;
}
@end
Objective-C的.語法,是一種語法糖,.haha用於=左邊是賦值,也就是set;.haha用於=右邊,是取值,也就是get。
當然,這三件事都是編譯器幫你生成程式碼,雖然沒有看到,但是確實是存在的。而分類中,就不會自動生成例項變數,所以需要手動關聯屬性。
而通過檢視category的定義,我們也可以看出一些端倪:
struct objc_category {
char * _Nonnull category_name OBJC2_UNAVAILABLE;
char * _Nonnull class_name OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
我們可以看到,category中,有例項方法列表instance_methods,類方法列表class_methods,屬性列表protocols,唯獨沒有例項變數列表:ivars。因此,我們只能通過其他的途徑去實現。
使用關聯物件
既然分類中,編譯器無法自動為屬性生成例項變數,也無法自動生成get/set方法,那麼我們只能在執行時動態的關聯屬性
如下:
#import "Person+Skill.h"
#import <objc/runtime.h>
static void *hahaKey = &hahaKey;
@implementation Person (Skill)
-(NSString*)haha{
return objc_getAssociatedObject(self, hahaKey);
}
-(void)setHaha:(NSString *)haha{
objc_setAssociatedObject(self, hahaKey, haha, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
如此一來,不會再有警告,也能夠正常的使用該屬性的例項變數,而不會crach:
person.haha = @"哈哈";
NSLog(@"%@",person.haha);
動態關聯的相關方法中,key值的幾種寫法,利用靜態變數地址唯一不變的特性
- 1、static const void *hahaKey = & hahaKey;
- 2、static const NSString * hahaKey = @"hahaKey";
- 3、static const char hahaKey;
或者這樣:
- 4、@selector(haha)
關聯策略是個列舉:
- OBJC_ASSOCIATION_ASSIGN = 0, //關聯物件的屬性是弱引用
- OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //關聯物件的屬性是強引用並且關聯物件不使用原子性
- OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //關聯物件的屬性是copy並且關聯物件不使用原子性
- OBJC_ASSOCIATION_RETAIN = 01401, //關聯物件的屬性是copy並且關聯物件使用原子性
- OBJC_ASSOCIATION_COPY = 01403 //關聯物件的屬性是copy並且關聯物件使用原子性
總結
- Category可以為主類新增方法,可以按照功能劃分不同的分類。
- Category不能為主類新增例項變數,但是可以通過
objc association
的方式來動態關聯屬性,達到同樣的效果。 - Category可以用來建立私有方法的前向引用,使得主類中的私有方法暴露無遺。
- Category可以依賴於主類,但是主類一定不依賴於Category,也就是說,移除Category,對主類沒有任何影響。就像為MacBook買了一個鍵盤,即插即用。
本文屬用法整理,而關於Category的底層實現沒有進行分析,暫時沒那個大神的能力(可通過文章開頭的參考進行檢視,裡面有關於底層的實現分析)。但是對於使用Category,本文應該是具有一定的參考作用的。如果您覺得本文對您有一定的幫助,請隨手點個喜歡,十分感謝!???
相關文章
- iOS問題整理03----CategoryiOSGo
- IOS category 與 extensioniOSGo
- 【iOS】category重寫方法的呼叫iOSGo
- iOS底層原理-CategoryiOSGo
- iOS設計模式——CategoryiOS設計模式Go
- iOS Extension Category Protrol 例子理解iOSGo
- iOS相關學習資料的整理iOS
- iOS[super class]和[self class]iOS
- 關於rpc的整理和理解RPC
- 關於oracle synonym 的總結整理Oracle
- [高翔]關於卷遷移的整理
- iOS套路面試題之CategoryiOS面試題Go
- iOS使用Category新增@property變數iOSGo變數
- 關於 iOS 中的庫iOS
- Category的本質<三>關聯物件Go物件
- iOS底層原理總結 - Category的本質iOSGo
- iOS -- 關於心情iOS
- 關於Mybatis中SQL語句的整理MyBatisSQL
- 關於MySQL event的一些整理MySql
- iOS runtime 給 Category 加屬性iOSGo
- 說說iOS中的常用的關鍵字static ,class(僅限Swift關鍵字)iOSSwift
- 關於IOS物件的小事的探究iOS物件
- 關於IOS測試iOS
- 關於 iOS 批量打包的總結iOS
- iOS 關於時間的處理iOS
- Object與Class的關係Object
- 基於AIX VIOS常用命令整理AIiOS
- JavaScript關於陣列的一些方法整理JavaScript陣列
- 關於快取和 Chrome 的“新版重新整理”快取Chrome
- 關於網路安全幾個問題的整理
- css+html關於文字的總結(整理中)CSSHTML
- 關於 資料壞塊 的整理和總結
- 關於iOS進階之路iOS
- iOS中擴充套件機制Category和associativeiOS套件Go
- Category 特性在 iOS 元件化中的應用與管控GoiOS元件化
- iOS 關於tabBar的幾處筆記iOStabBar筆記
- 【iOS】關於 UICollectionView 的自定義佈局iOSUIView
- iOS開發 關於Super的題目iOS