2011-06-14 78 views
4

由於從C++到Objective-C我的轉型過程的一部分,我集中讀書Cocoa and Objective C Up and Running.目標C:類方法說明

在書中代碼的例子之一,有一條線,它沒有什麼意義我與我目前的知識水平:

它是類方法+ (Photo*) photo;的聲明。

任何人可以解釋我的理由,請作者爲什麼決定該方法(Photo*) photo;將其申報爲類的方法,而不是實例方法

我已經studiet的理論,認爲instane方法是像一個類成員函數和類方法是一樣的東西靜態函數在C++中。但這仍然不能回答我的問題。

下面是聲明代碼:

#import <Foundation/Foundation.h> 


@interface Photo : NSObject{ 

    NSString* caption; 
    NSString* photographer;  
} 

+ (Photo*) photo; 

- (NSString*) caption; 
- (NSString*) photographer; 

- (void) setCaption: (NSString*)input; 
- (void) setPhotographer: (NSString*)input; 

@end 

的實現代碼如下:

#import "Photo.h" 


@implementation Photo 

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     [self setCaption:@"Default Caption"]; 
     [self setPhotographer:@"Default Photographer"]; 
    } 

    return self; 
} 


+ (Photo*) photo { 
    Photo* newPhoto = [[Photo alloc] init]; 
    return [newPhoto autorelease]; 
} 


- (NSString*) caption { 
    return caption; 
} 


- (NSString*) photographer { 
    return photographer; 
} 


- (void) setCaption:(NSString *)input { 
    [caption autorelease]; 
    caption = [input retain]; 
} 


- (void) setPhotographer: (NSString *)input { 
    [photographer autorelease]; 
    photographer = [input retain]; 
} 


- (void)dealloc 
{ 
    [self setCaption:nil]; 
    [self setPhotographer:nil]; 

    [super dealloc]; 
} 

@end 
+2

該方法聲明,有趣的是,不正確。所有初始化器都應該返回'id',構造器應該使用'self'(它指的是類方法內的類),而不是硬編碼的類名稱。爲了使子類別正常工作,這兩件事是必需的。編輯:我看到bbum已經在下面提到了這一點,但我認爲它重複。 – 2011-06-15 01:12:59

+0

@Josh完全;在下面的meta-answer中進行了擴展。 – bbum 2011-06-15 15:47:17

回答

0

有人可以解釋我的原因,請問,爲什麼作者已經決定了方法(照片*)照片;將其聲明爲類方法而不是實例方法?

它基本上構造一連串的包裝。注意來源:

+ (Photo*) photo { 
    Photo* newPhoto = [[Photo alloc] init]; 
    return [newPhoto autorelease]; 
} 

分配一個新的照片,初始化它,標記它autorelease,並返回它。由於它創建的對象,沒有對象尚未操作時,ERGO這必須是一個類的方法。

+0

+1,你好邁克。完美解釋。謝謝。因此,如果我理解正確,那麼當方法id聲明爲類方法而非實例方法時,這是極少數情況之一。 – 2011-06-14 22:28:27

+0

儘管所有的答案都是正確的,但我認爲,這個問題以最清晰的方式解釋了我的問題。因爲我只能選擇一個答案作爲*可接受的答案*,所以我想標記這個答案。 – 2011-06-14 22:46:15

+2

有一個問題;該方法應該被聲明爲返回'id'並且應該返回[[[self alloc] init] autorelease];'(一行或兩行,無所謂 - 只需直接引用Class)。事實上,「照片」將是一個子類化的痛苦。 – bbum 2011-06-14 22:50:40

1

+photo就像是一個構造函數。你需要一種方式來獲得一個對象發送實例的方法,這給你一個自動釋放的一個。

+0

+1,嗨,傑里米,謝謝你的回答。如果我將該方法聲明爲實例方法,會發生什麼?我可以用它創建對象嗎? – 2011-06-14 22:23:49

+2

不,因爲你會有一個雞和雞蛋的問題:你如何得到一個實例發送實例方法的對象?在這種情況下,'-photo'實例方法與構造函數相比更像'-copy'或'-clone'。 – 2011-06-14 22:26:01

+0

現在,我明白了。謝謝你,傑里米。 – 2011-06-14 22:29:37

3

在這種情況下,photo是一種方便的方法,它會返回該類的autoreleased實例。

由於照片的目的是爲了給你一個實例,所以將它作爲一個需要你已經擁有一個實例的實例方法是沒有意義的。

如果您熟悉工廠方法,照片方法與此類似。

+1

+1 -Hi Michael。在你身邊完美地解釋,並在我的理解。謝謝。 – 2011-06-14 22:37:23

7

+ (Photo*) photo方法是一個Factory Method,它封裝了創建類的對象的細節。

工廠方法強制 封裝,並允許在不不可分割 耦合到創造行爲請求一個目的是 。

在這個特定的例子中,由工廠方法隱藏的信息是memory management,因爲客戶端不需要擔心釋放返回的對象。

這是一個Objective-C API中的常見做法,用於在返回相同類的自動釋放對象的類中提供工廠方法。這些方法不能包含任何「alloc」,「new」,「copy」或「mutableCopy」這些單詞,根據約定,這些單詞表示調用方不擁有返回的對象,即它不必須明確發佈。

相關資源:

+0

+1 -Hi Enrico。謝謝你的解釋。 – 2011-06-14 22:32:02

1

它相當於一個靜態方法,如你所說。在這種情況下(和[ClassName className]方法的所有情況),它基本上是工廠方法。你要求班級構建一個自己的實例並將其傳回。所有這些方法都應該返回一個自動釋放對象。

如果你願意,你可以放心地忽略這樣的方法 - 通常會有一個alloc + init的等價物,但是使用類方法通常更方便,特別是如果你創建一個throaway對象而不想保留它。

最後,你有時會發現這需要您使用類方法,因爲他們會隱瞞一些聰明的邏輯,其中的實例另一類實際返回的類。你有時會聽到這些被描述爲「班級集羣」。

+0

類集羣可以很好地處理標準的alloc-init跳舞。只是'-init'幾乎肯定會返回一個不同於'-alloc'的對象。例如,請參閱'NSString'或'NSArray',其中alloc-init可以正常工作以構建新實例。 – 2011-06-14 22:27:14

+0

+1 -Hi Thom,並感謝您的解釋。你甚至提供了一些更有用的信息。我明白你的意思。 – 2011-06-14 22:43:47

4

元回答:

的一個問題;該方法應該是 聲明爲返回ID並且應該 返回[[[self alloc] init] autorelease]; (一行或兩行, 無所謂 - 只需直接參考 )。事實上,照片 將是一個子類的痛苦。

展開式 - 這給出:

+ (Photo*) photo { 
    Photo* newPhoto = [[Photo alloc] init]; 
    return [newPhoto autorelease]; 
} 

如果類的子類了,這個工廠方法不會沒有被覆蓋幾乎做同樣的事情工作。但是,由於Objective-C不支持協方差和反差,因此無法聲明子類的實現返回子類的一個實例,而且還沒有運行編譯器警告的重大風險。或者,您可以將返回值向下放到更具體的類中,但這很脆弱。

相反,這樣做:

+ (id) photo { 
    id newPhoto = [[self alloc] init]; 
    return [newPhoto autorelease]; 
} 

這解決了這兩個問題:

  • ,因爲它使用self,它會實例化任何類的實例,它的實現上,其中包括的子類Photo

  • ,因爲它返回id,來電者都可以做沒有問題如下:

    照片* p = [寫真照片] SubclassOfPhoto * s = [SubclassOfPhoto photo];

+0

因此,使'照片'一個真正的工廠方法,在該子類不需要定義自己的版本。 – 2011-06-15 20:06:17

+0

確切地說;事實上,它是一個硬連線到一個特定班級的工廠。對於類集羣和其他類似的模式不太好。 – bbum 2011-06-15 20:45:34