2013年5月29日 星期三

Categories -- 修改現有的類別

使用時機:

想為已經存在的類別新增或修改方法(不建議修改原本的方法,因為繼承他的子類別也會受影響),你或許會問,那為什麼不在原本的.h .m檔中新增就好,幹嘛這麼麻煩使用categories,因為你有可能拿不到原本source code或是沒有權限修改(例如 NSString),而且如果大家都在同一份中作修改,那會改的亂七八糟的,這時候依功能把它獨立出來,個人寫個人的,就方便許多。


Dog.h
#import <Foundation/Foundation.h>

@interface Dog : NSObject
{
    NSString *_name;
}
-(id)initWithName:(NSString *)name;
-(void)play;

@end

Dog.m
#import "Dog.h"

@implementation Dog

-(id)initWithName:(NSString *)name
{
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

-(void)play
{
    NSLog(@"%@ is playing.",_name);
}

@end

這隻狗只會玩,幫他添加點聲音,新增Category檔案
選擇Category on “Dog”
Dog+Bark.h
#import "Dog.h"

@interface Dog (Bark)

-(void)barkWaWa;
-(void)barkMeMe;

@end

Dog+Bark.m
#import "Dog+Bark.h"

@implementation Dog (Bark)

-(void)barkWaWa
{
    NSLog(@"%@ WaWa !!",_name);
}
-(void)barkMeMe
{
    NSLog(@"%@ MeMe !!",_name);
}


@end

從檔名可以看出來Category是附加在原本的類別上的,我們把關於叫聲的方法都放在Bark這個Category,要注意的是 Dog (Bark)的寫法,是用小刮號表示,另外在Category無法新增var,只能增加方法(可以宣告不一定每個都實作出來),如果要add instance variable,請用extensions。

main.m
#import <Foundation/Foundation.h>
#import "Dog.h"
#import "Dog+Bark.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Dog *d = [[Dog alloc]initWithName:@"Tom"];
        [d play];
        [d barkWaWa];
        [d barkMeMe];
    }
    return 0;
}

現在它除了會玩之外還會叫了,特別要注意的是,所有繼承於Dog類別的子類別也都學會叫囉。


Informal Protocols

category 有時也稱作 informal protocol,常常我們在 root class 時,會一併宣告 category,此時並不實作出這些方法(category.m 沒有 implement),而是等到子類別時,才選擇要實現哪些方法,在子類別的 .h中重新宣告,.m 中實作。那可能有人會問,這麼麻煩幹麼,都要在子類別重新宣告了,category 還有用的必要嗎,其實這時候 category 有點像是把這些方法先文件化、模組化,統一放在一個根類別加以說明,而不要四散在各處,這讓以後的人比較容易了解此類別的用途。

Private Method

在Objective-C裡頭,方法的修飾不像 instance有@public, @private, @protected,宣告時放在.h 的是public, 放在 .m的是private,That's all,那這個跟Category有什麼關係,原來是放在.m的寫法需要用到,category的名稱是空白的,匿名Category,其實這就是 Class Extension

@interface Dog()

 //private method
-(void) privateMethod;

@end

沒有留言: