【ObjC】@interface类名(categoryName)
2014-12-24 11:07
288 查看
刚了解ObjC不久,有看到类似下面代码
[cpp] view
plaincopy
@interface ClassName ( CategoryName )
// method declarations
@end
对应的头文件一般定义为下面的格式
[cpp] view
plaincopy
ClassName+CategoryName.h
查了下才知道这是所谓的ObjC的所谓类扩展的方法
OOP的精神之一,就是如果你想研發一台新款式的車子,你並不需要重新發明輪子,通常的做法會去繼承某個現有的”車子類別”,然後加上你要的功能跟屬性,改一改就變成一款新的車子可以來騙錢了。
不過有時候你想幫原來的類別加功能,但又不想動到原來的程式碼,例如你可能下載了某款功能超強的2D物理引擎程式碼,但因為某些小地方寫的不合你的需求,於是你便動手改原始碼來加功能。這當然沒問題,但萬一原作出新的版本,你要不就選擇維持自己原來的版本不update,不然就是update之後,你原來加在舊版本的程式碼得再重貼一次到新版。
Objective-C裡有個叫做
class,都是在不影響或修改原來的類別或模組的情況下去修改原有的功能。
舉個例子,因為NSObject是所有物件的源頭,但我想要加一個方法讓所有的子類別都可用(把要加的功能放在繼承階層的最源頭並不是好的設計,在這裡只是舉個例子而已)。程式碼這樣寫:
//
interface
@interface
NSObject(MySuperObject)
-(void)
printRetainCount;
+(void)
sayHello;
@end/
/
implementation
@implementation
NSObject(MySuperObject)
-(void)
printRetainCount
{
NSLog(@"The
retain count is %d",
[self
retainCount]);
}
+(void)
sayHello
{
NSLog(@"Hello
everybody!");
}
@end
這裡用的是在後面加個小括號以及category的名稱。要注意的是category只能加method(instance
method或是class method都行),沒辦法增加instance variable(其實也不是完全不行,只是可能要用一些怪招,不過如果要做到這種程度,是不是該考慮直接用一般的繼承就好?)。使用起來的樣子:
//
建立Book物件
Book
*b
=
[[Book
alloc]
init];
//
instance method from category
[b
printRetainCount];
//
用完放掉
[b
release];
//
class method from category
[Book
sayHello];
上面這段程式碼如果一般的情況下,在編譯階段就會跳出警告(認不得printRetainCount跟sayHello這兩個方法),硬是執行的話就會直接錯誤。但因為我們已經有了category的加持,所以執行結果會是:
因為category是在原來的類別裡加功能,所以你可能會想萬一原來的類別裡有個跟你的category同名的方法怎麼辦? 答案是,會以category的定義為主,也就是原來類別裡的那個方法就被你蓋掉了,當然這不見得是你想要的結果。所以通常這種方法擴充的,會建議可以在前面加個prefix,避免跟原來的方法有重複而造成不幸的結果。
另外,前面有篇提到protocol的文章,也提到了
[cpp] view
plaincopy
@interface ClassName ( CategoryName )
// method declarations
@end
对应的头文件一般定义为下面的格式
[cpp] view
plaincopy
ClassName+CategoryName.h
查了下才知道这是所谓的ObjC的所谓类扩展的方法
OOP的精神之一,就是如果你想研發一台新款式的車子,你並不需要重新發明輪子,通常的做法會去繼承某個現有的”車子類別”,然後加上你要的功能跟屬性,改一改就變成一款新的車子可以來騙錢了。
不過有時候你想幫原來的類別加功能,但又不想動到原來的程式碼,例如你可能下載了某款功能超強的2D物理引擎程式碼,但因為某些小地方寫的不合你的需求,於是你便動手改原始碼來加功能。這當然沒問題,但萬一原作出新的版本,你要不就選擇維持自己原來的版本不update,不然就是update之後,你原來加在舊版本的程式碼得再重貼一次到新版。
Objective-C裡有個叫做
category的東西可以幫你在現有的類別加上新功能,這樣一來上面這個問題就可以搞定了。跟別的程式語言比較起來,category的觀念有點像是在Ruby的mixin或是Python的open
class,都是在不影響或修改原來的類別或模組的情況下去修改原有的功能。
舉個例子,因為NSObject是所有物件的源頭,但我想要加一個方法讓所有的子類別都可用(把要加的功能放在繼承階層的最源頭並不是好的設計,在這裡只是舉個例子而已)。程式碼這樣寫:
//
interface
@interface
NSObject(MySuperObject)
-(void)
printRetainCount;
+(void)
sayHello;
@end/
/
implementation
@implementation
NSObject(MySuperObject)
-(void)
printRetainCount
{
NSLog(@"The
retain count is %d",
[self
retainCount]);
}
+(void)
sayHello
{
NSLog(@"Hello
everybody!");
}
@end
這裡用的是在後面加個小括號以及category的名稱。要注意的是category只能加method(instance
method或是class method都行),沒辦法增加instance variable(其實也不是完全不行,只是可能要用一些怪招,不過如果要做到這種程度,是不是該考慮直接用一般的繼承就好?)。使用起來的樣子:
//
建立Book物件
Book
*b
=
[[Book
alloc]
init];
//
instance method from category
[b
printRetainCount];
//
用完放掉
[b
release];
//
class method from category
[Book
sayHello];
上面這段程式碼如果一般的情況下,在編譯階段就會跳出警告(認不得printRetainCount跟sayHello這兩個方法),硬是執行的話就會直接錯誤。但因為我們已經有了category的加持,所以執行結果會是:
The retain count is 1 Hello everybody!
因為category是在原來的類別裡加功能,所以你可能會想萬一原來的類別裡有個跟你的category同名的方法怎麼辦? 答案是,會以category的定義為主,也就是原來類別裡的那個方法就被你蓋掉了,當然這不見得是你想要的結果。所以通常這種方法擴充的,會建議可以在前面加個prefix,避免跟原來的方法有重複而造成不幸的結果。
另外,前面有篇提到protocol的文章,也提到了
informal protocol,其實它就是一種依附在NSObject上,但是沒有把功能實作出來的category。一般的protocol必需乖乖實作所有@required的方法(在Objective-C 2.0以前全部預設都是@required),但在informal protocol並沒有強制規定全部都要實作出來。事實上,在Objective-C 2.0之後才在protocol裡加進來的@optional語法,就是打算用來取代informal protocol的,在比較新版本的SDK大多都是用標準的protocol在寫了。
相关文章推荐
- 【ObjC】@interface类名(categoryName)
- 编译报错:Undefined symbols for architecture arm64: "_OBJC_CLASS_$_类名", referenced from
- ObjC(Objective-C)中的"非正式协议(interface)"与"正式协议(protocal)"
- objc 之category的理解
- objc category的秘密
- Java反射:类名.class、class.forName()、对象.getClass区别 详解
- Spring mvc (五) [ControllerClassNameHandlerMapping根据Controller类名匹配,解决了bean的递增配置问题]
- Attempt to invoke interface method 'java.lang.Object[] java.util.Collection.toArray()' on a null obj
- Question( category_id 关联 category_name)
- 类名.class, class.forName(), getClass()区别
- C# 因缺少CategoryName,而未能初始化 的解决办法
- Objc-C 知识点回顾 八 NSDate、 Extension、Category、Delegate
- How to change network interface name
- Magento: 通过category name获取category信息
- category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性
- 根据类名创建类Class.forname
- vs2008报错 libcmtd.lib(undname.obj) : fatal error LNK1190: 找到无效的链接地址信息,请键入 0x0002
- getClassName防止多个类名
- category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性
- objc@interface的设计哲学与设计技巧