2013年5月29日 星期三

Class Extensions Example -- add private function

上一篇講到Categories的用法時,提到了它無法新增var,那如果我要新增var又該怎麼辦,這時候class extension就派上用場了,class extension 和category很像,但又有一些不同,class extension又稱為匿名的category。

相同點:都用來修改現有的類別
不同點:
  1. Category 只能新增或修改方法,無法新增變數
  2. Category 中所宣告的方法不用一定要全部實作,但是class extension宣告的方法都必須實現
  3. Category 方法的implement code必須放在原本類別的.m檔中
  4. Class extension 所宣告的var and function都是private

使用時機:引用Apple官方文件,“Class extensions are often used to extend the public interface with additional private methods or properties for use within the implementation of the class itself.”

以上篇的Dog為基底,我們來擴充一下,新增一個Class extension檔,輸入Extension name


這時候只會產生一個.h檔 Dog_Identification.h,因為要在原本的類別中實作


Dog_Identification.h
#import "Dog.h"

@interface Dog ()
{
    NSString *_secret;
}

-(NSString *)secret;
-(void)setSecret:(NSString*)s;

@end

括弧內沒有東西,所以這也是為什麼它稱為 匿名的Category的原因。


在原本的Dog.m檔中import此標頭檔,記得不是在Dog.h,因為如果你在Dog.h import Dog_Identificaton.h,又在Dog_Identification.h import Dog.h,這樣互相import會出錯的。


Dog.m
#import "Dog.h"
#import "Dog_Identification.h"

@implementation Dog

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

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

-(NSString *)secret
{
    return _secret;
}
-(void)setSecret:(NSString*)s
{
    _secret = s;
}

-(NSString *)giveMeTheSecret
{
    return [self secret];
}

@end

實作完Class extension functon,另外在Dog.h宣告一個 giveMeTheSecret方法,去調用 -(NSString *)secret 這個private function,因為外部的類別是無法使用private function的。 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];
        NSLog(@"The secret is %@.",[d giveMeTheSecret]);
    }
    return 0;
}


BTW,很多人在使用Class Extension時,是不會去產生一個.h檔的,而是直接在原本類別的.m檔中去做宣告,所以我們這個範例可以改為如下,把Dog_Identification.h刪掉

Dog.m

#import "Dog.h"

@interface Dog ()
{
    NSString *_secret;
}

-(NSString *)secret;
-(void)setSecret:(NSString*)s;

@end


@implementation Dog

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

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

-(NSString *)secret
{
    return _secret;
}
-(void)setSecret:(NSString*)s
{
    _secret = s;
}

-(NSString *)giveMeTheSecret
{
    return [self secret];
}

@end




沒有留言: