2014-10-03 45 views
27

我們這個新的宏被XCode中6介紹:NS_DESIGNATED_INITIALIZERiOS的指定初始化:使用NS_DESIGNATED_INITIALIZER

我在網上搜索,但不能真正找到任何好的文檔,至於怎麼用這個。

在語法上,我們可以用它喜歡:

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; 

但什麼是標有這個宏的初始值的可能的優勢,也是我們應該尋找的東西用這個當?

我主要感興趣的是這個宏的用例。任何鏈接/文件將不勝感激。

回答

44

採用NS_DESIGNATED_INITIALIZER是很好在http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html解釋:

The designated initializer guarantees the object is fully initialised by sending an initialization message to the superclass. The implementation detail becomes important to a user of the class when they subclass it. The rules for designated initializers in detail:

  • A designated initializer must call (via super) a designated initializer of the superclass. Where NSObject is the superclass this is just [super init].
  • Any convenience initializer must call another initializer in the class - which eventually leads to a designated initializer.
  • A class with designated initializers must implement all of the designated initializers of the superclass.

作爲一個例子,如果接口是

@interface MyClass : NSObject 
@property(copy, nonatomic) NSString *name; 
-(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; 
-(instancetype)init; 
@end 

則編譯器檢查是否(便利)初始化init調用 的(指定)初始化程序initWithName:,所以這會引起警告:

-(instancetype)init 
{ 
    self = [super init]; 
    return self; 
} 

,這將是確定:

-(instancetype)init 
{ 
    self = [self initWithName:@""]; 
    return self; 
} 

斯威夫特的有關規定確定的和方便的初始化是更嚴格, 如果你混的Objective-C和斯威夫特代碼,標誌着指定目標-C初始化器幫助編譯器執行規則。

例如,這斯威夫特子類會導致編譯器錯誤:

class SwClass: MyClass { 
    var foo : String 
    init(foo : String) { 
     self.foo = foo 
     super.init() 
    } 
} 

,這將是確定:

class SwClass: MyClass { 
    var foo : String 
    init(foo : String) { 
     self.foo = foo 
     super.init(name: "") 
    } 
} 
+2

Objective-C中的概念並不是很好的想法,因爲'initWithName:@「」'在進行子類化時並不總是有意義的。相反,通常從超類中重寫的指定初始化器應該拋出異常,說使用來自子類的指定初始化器。 – Andy 2015-10-18 15:47:23

+5

要添加到Martin的答案,您可能想要完全禁止用戶調用默認的初始化程序,在這種情況下,您可以使用以下內容: - (instancetype)init NS_UNAVAILABLE; – 2016-02-18 16:21:28

1

指定的初始定義我們如何繼承結構時,我們的初始化;他們是你的班級的「規範初始化者」。無論您調用超類鏈中的哪個指定初始值設定項,它都保證可靠,並始終從最遠的祖先到最遠的後代。

指定的初始化程序未定義創建對象時應使用的初始化程序。這在https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns中有詳細解釋。

6

我最常用的方式做到這一點:

@interface Person : NSObject 

- (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER; 
- (nullable instancetype)init NS_UNAVAILABLE; 

@property (nonatomic, nonnull) NSString *name; 

@end 

而且實現

@implementation Person 

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

@end 

在這種情況下,你不應該重寫你的超類方法的NS_DESIGNATED_INITIALIZERNSObjectinit:在這種情況下) - 我們使用NS_UNAVAILABLE將此方法標記爲不需要。或者您可以覆蓋它以使用默認參數調用指定的初始化程序。