分類-Category
1. 基本用途
- 如何在不改變原來類模型的前提下,給類擴充一些方法?有2種方式
- 繼承
- 分類(Category)-- 可以給某一個類擴充一些方法(不修改原來類的代碼)
2. 格式
- 分類的聲明
@interface 類名 (分類名稱)
// 方法聲明
@end
- 分類的實現
@implementation 類名 (分類名稱)
// 方法實現
@end
3. 好處
- 一個龐大的類可以分模塊開發
- 一個龐大的類可以由多個人來編寫,更有利于團隊合作
4. 給系統自帶的類添加分類
- 給NSString增加一個類方法:計算某個字符串中阿拉伯數字的個數
- 給NSString增加一個對象方法:計算當前字符串中阿拉伯數字的個數
5. 注意
- Category可以訪問原始類的實例變量,但不能添加變量,只能添加方法。如果想添加變量,可以考慮通過繼承創建子類
- Category可以實現原始類的方法,但不推薦這么做,因為它是直接替換掉原來的方法,這么做的后果是再也不能訪問原來的方法
- 多個Category中如果實現了相同的方法,只有最后一個參與編譯的才會有效
類的本質
1. 類也是個對象
- 其實類也是一個對象,是Class類型的對象,簡稱“類對象”
- Class類型的定義
typedef struct objc_class *Class;
- 類名就代表著類對象,每個類只有一個類對象
2. +load和+initialize
-
+load
- 在程序啟動的時候會加載所有的類和分類,并調用所有類和分類的+load方法
- 先加載父類,再加載子類;也就是先調用父類的+load,再調用子類的+load
- 先加載元原始類,再加載分類
- 不管程序運行過程有沒有用到這個類,都會調用+load加載
-
+initialize
- 在第一次使用某個類時(比如創建對象等),就會調用一次+initialize方法
- 一個類只會調用一次+initialize方法,先調用父類的,再調用子類的
3. 獲取類對象的2種方式
Class c = [Person class]; // 類方法
或者
Person *p = [Person new];
Class c2 = [p class]; // 對象方法
4. 類對象調用類方法
Class c = [Person class];
Person *p2 = [c new];
description方法
1. -description方法
使用NSLog和%@輸出某個對象時,會調用對象的-description方法,并拿到返回值進行輸出
2. + description方法
使用NSLog和%@輸出某個類對象時,會調用類對象+description方法,并拿到返回值進行輸出
3. 修改NSLog的默認輸出
- 重寫-description或者+description方法即可
4. 死循環陷阱
- 如果在-description方法中使用NSLog打印self
SEL
1. 方法的存儲位置
- 每個類的方法列表都存儲在類對象中
- 每個方法都有一個與之對應的SEL類型的對象
- 根據一個SEL對象就可以找到方法的地址,進而調用方法
- SEL類型的定義
typedef struct objc_selector *SEL;
2. SEL對象的創建
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
3. SEL對象的其他用法
// 將SEL對象轉為NSString對象
NSString *str = NSStringFromSelector(@selector(test));
Person *p = [Person new];
// 調用對象p的test方法
[p performSelector:@selector(test)];
NSLog輸出增強
- __ FILE __ :源代碼文件名
- __ LINE __ :NSLog代碼在第幾行
- _cmd :代表著當前方法的SEL
// 下面的代碼會引發死循環
- (void)test
{
[self performSelector:_cmd];
}