2012-08-06 49 views
7

我是Objective-C中的新成員,我試圖創建基於Apple's documentation的單例類。super allocWithZone在單例類概念中存在一些疑問

+ (MyGizmoClass*)sharedManager 
{ 
    if (sharedGizmoManager == nil) { 
     sharedGizmoManager = [[super allocWithZone:NULL] init]; 
    } 
    return sharedGizmoManager; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    return [[self sharedManager] retain]; 
} 

在此代碼中sharedManager是一個靜態方法,它將檢查此類的對象是否存在。如果是這樣,它將返回先前創建的對象,否則它將創建一個新對象。

我有一些問題:

  1. 如果sharedManager是靜態的,怎麼能訪問super

  2. 當我打印[super class]爲什麼它給當前的類名?

  3. 爲什麼[[super allocWithZone:NULL] init]返回當前類對象?

  4. 如果super等於self這裏比爲什麼它不叫電流類的allocWithZone:(NSZone *)zone

+0

你可以看看[我以前的文章關於單例模式實現](http://stackoverflow.com/questions/6912703/objective-c-static-field-and-implementing-singleton-pattern/6913036#6913036 )。如果在實施代碼中提出了很多評論。希望這會有所幫助 – 2012-08-06 11:52:42

+0

你爲什麼分配超級?你不想要一個自我的例子嗎? – 2013-08-06 17:26:35

+0

這是一個令人驚訝的舊文件。 – 2013-08-06 17:26:44

回答

3

其他答案,雖然他們指出關於單身人士的良好信息,但實際上並沒有回答你的問題。你的問題實際上主要基於對象定位,你特別引用單例的事實是偶然的。

  1. 我回答this question參考self,這裏是意譯,答案

    super確實有一流水平的上下文意思的重要組成部分,但它指的是超類本身,而不是實例

  2. 這一個也扔了我。我問this question而且得出結論:

    [super class]呼籲當前實例(即self)的super方法。如果自我有一個被覆蓋的版本,那麼它會被調用,它會看起來不同。由於您不覆蓋它,因此致電[self class]與致電[super class]相同。

  3. 你確定它實際上是返回這個類的實例嗎?還是你將它分配給這個類的實例sharedGizmoManager

  4. 超級並不等於自我,但您調用的一些方法如: [super class]正在調用[self class]將調用的方法的相同實現。

+2

我認爲#2錯過了標記。 super,一個不能被重寫的*關鍵字,將消息發送給超類。在一個靜態+方法中(這不是真正的靜態方法,而是* Class *類的動態方法),超類是一個* NSObject *。 *當用'super'調用時,NSObject *的* class *方法在靜態方法中返回子類,所以'[self class] == [super class]'。 – 2013-08-03 00:56:16

+0

NSObject的實現如下所示: '+(Class)class return self; }' - 'self'在這種情況下,就是子類,因爲那是你發送消息的地方。 '+(Class)superclass'將會產生所需的效果,在這種情況下你需要'[self superclass];'(note + method)。 – Ephemera 2013-08-03 01:31:46

+0

@RiazRizvi,隨意修改答案! – 2013-08-05 14:54:30

3

這裏有幾件事要考慮。首先,Cocoa Fundamentals指南已經過時了。它沒有考慮到Apple開發的一些當前技術,如Grand Central Dispatch和Automated Reference Counting。您的allocWithZone方法中的[retain]在啓用ARC的項目中無法正確編譯(因爲您是Obj-C的新手,我在此假設您是iOS/iPhone的新手,所以您應該閱讀這兩項技術)。

有過在這個線程不同的單身人士設計模式的一個很好的討論: What should my Objective-C singleton look like?

當然,這是一個較舊的線程,因此不會考慮自動引用計數(我使用路易Gerbang多年的答案,它不再適用於啓用ARC的項目)。

對於啓用ARC-項目/文件(是可以啓用ARC只是單個文件) - 我們已經遷移到使用GCD和作品相當不錯的單身:

static YourClassName * volatile sharedInstance = nil; 

+ (YourClassName *)sharedInstance 
{ 
    static dispatch_once_t sharedInstanceToken; 
    dispatch_once(&sharedInstanceToken, ^{ 
     sharedInstance = [[YourClassName alloc] init]; 
    }); 
    return sharedInstance; 
} 

這是怎麼回事?那麼如果你看看GCD docs,你會發現dispatch_once只在一個特定對象的應用程序的整個生命週期中執行一次。隨着文檔的發展,這對於以線程安全的方式創建單例非常有用。

最重要的是,我們將sharedInstance方法聲明爲volatile,這意味着編譯器/運行時不應該嘗試緩存對該方法的調用,並應始終執行其中的代碼。這確保我們總是調用GCD,並且我們總是找回所需的對象。

由於您是Obj-C的新手,所以我正在爲這一羣人着想,但是您可以先看一下GCD,ARC,然後一旦您在Obj-C中有一個堅實的基礎,考慮IMP緩存,這是什麼波動是防止發生。

+0

偉大的答案,我最近切換到這種創建單身人士的方式,但我從來沒有聽說過揮發性這個詞! – 2012-08-06 11:32:06

+0

儘管你提供了有關單身人士的良好信息,但他們只是偶然引用他們。問題實際上是關於oop以及調用哪些方法的實現。 – 2012-08-06 12:30:35

+3

「我們將sharedInstance方法聲明爲volatile」 - 但是您聲明瞭靜態變量volatile,而不是方法。 Objective-C中不存在易失性方法,並且方法調用永遠不會被優化。相反,您應該在方法內移動靜態變量。這保證了在不調用方法的情況下永遠不會訪問它。 – nschum 2013-02-10 22:27:45

3

(1.)什麼是'靜態函數'中的super?在Objective-C中,+方法被正確地稱爲類方法, - 方法被稱爲實例方法。這些+方法不是真正的靜態方法,因爲Objective-C classes are themselves objects of an opaque type called Class。因此superself都在+方法中定義。 super將消息發送到MyGizmoClass的超類,但是當從+方法調用super查找等效的方法時,並且當從方法super中調用時查找對應的方法。
selfMyGizmoClass返回MyGizmoClass其爲一個類,而在 - 方法self +方法是一個指向MyGizmoClass實例。 (2.)+class方法返回self.isa。是[super class]調用超類:+class方法,但是,當self傳遞給+方法時,其值和其類型都不會被修改(而self的類型在通過方法傳遞時轉換爲超類)。所以當執行+class方法上鍊要求self.isa時,它得到相同的值,MyGizmoClass
要確定,你可以驗證super確實通過從MyGizmoSuperClass獲得MyGizmoClass調用父類+class在那裏你可以放置一個覆蓋:

@interface MyGizmoSuperClass : NSObject 
    @end 
    @implementation MyGizmoSuperClass 
    +(Class) class { 
     NSLog(@"yes it calls MyGizmoSuperClass:class"); 
     return [super class]; 
    } 
    @end 
    @interface MyGizmoClass : MyGizmoSuperClass 
    +(Class) classviasuper; 
    @end 
    @implementation MyGizmoClass 
    +(Class) classviasuper { 
     return [super class]; //which version of class will super call? 
    } 
    @end 
    int main(int argc, char *argv[]) 
    { 
     NSLog(@"returned %@",[MyGizmoClass classviasuper]); 
    } 

打印

是它調用MyGizmoSuperClass:類
返回MyGizmoClass

(3)再次super調用的allocWithZone超類版本,但傳遞給方法仍指向MyGizmoClassself值,因爲allocWithZone返回接收器的類的對象,你會得到一個MyGizmoClass回來。

(4.)您可以輕鬆驗證superself不同。如果你實現了[self allocWithZone:NULL],你的代碼將會調用MyGizmoClassallocWithZone的實現並無限循環。用[super allocWithZone:NULL],超類的版本被調用。