iOS 指定初始化器:使用 NS_DESIGNATED_INITIALIZER
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26185239/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS Designated Initializers : Using NS_DESIGNATED_INITIALIZER
提问by Mehul Parmar
We have this new macro being introduced in XCode 6 : NS_DESIGNATED_INITIALIZER
我们在 XCode 6 中引入了这个新宏:NS_DESIGNATED_INITIALIZER
I searched on the net, but couldn't really find any good documentation as to how to use this.
我在网上搜索,但找不到关于如何使用它的任何好的文档。
Syntactically, we can use it like :
在语法上,我们可以像这样使用它:
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
But what are the possible advantages of marking an initializer with this macro, and also what are the things we should be looking at when using this ?
但是用这个宏标记初始化器的可能优点是什么,以及我们在使用它时应该注意什么?
I am mainly interested in the use cases of this macro. Any links / documentation would be appreciated.
我主要对这个宏的用例感兴趣。任何链接/文档将不胜感激。
回答by Martin R
The use of NS_DESIGNATED_INITIALIZER
is nicely explained in http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html:
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.
指定的初始化器通过向超类发送初始化消息来保证对象被完全初始化。对类的用户进行子类化时,实现细节变得很重要。指定初始化器的详细规则:
- 指定构造器必须(通过 super)调用超类的指定构造器。其中 NSObject 是超类,这只是 [super init]。
- 任何便利构造器都必须调用类中的另一个构造器——这最终会导致指定构造器。
- 具有指定初始值设定项的类必须实现超类的所有指定初始值设定项。
As an example, if your interface is
例如,如果您的界面是
@interface MyClass : NSObject
@property(copy, nonatomic) NSString *name;
-(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
-(instancetype)init;
@end
then the compiler checks if the (convenience) initializer init
calls
the (designated) initializer initWithName:
, so this would cause a warning:
然后编译器检查(便利)初始化程序是否init
调用(指定)初始化程序initWithName:
,因此这会导致警告:
-(instancetype)init
{
self = [super init];
return self;
}
and this would be OK:
这样就可以了:
-(instancetype)init
{
self = [self initWithName:@""];
return self;
}
In Swiftthe rules about designated and convenience initializers are even more strict, and if you mix Objective-C and Swift code, marking the designated Objective-C initializers helps the compiler to enforce the rules.
在Swift 中,关于指定初始化器和便利初始化器的规则更加严格,如果你混合使用 Objective-C 和 Swift 代码,标记指定的 Objective-C 初始化器有助于编译器强制执行这些规则。
For example, this Swift subclass would cause an compiler error:
例如,这个 Swift 子类会导致编译器错误:
class SwClass: MyClass {
var foo : String
init(foo : String) {
self.foo = foo
super.init()
}
}
and this would be OK:
这样就可以了:
class SwClass: MyClass {
var foo : String
init(foo : String) {
self.foo = foo
super.init(name: "")
}
}
回答by Timur Bernikovich
My most common way to do this:
我最常用的方法是:
@interface Person : NSObject
- (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)init NS_UNAVAILABLE;
@property (nonatomic, nonnull) NSString *name;
@end
And implementation
和实施
@implementation Person
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
self.name = name;
}
return self;
}
@end
In this case you should not override NS_DESIGNATED_INITIALIZER
of your superclass method (NSObject
's init:
in this case) - we used NS_UNAVAILABLE
to mark this method as unneeded. Or you can override it to call your designated initializer with default parameters.
在这种情况下,您不应覆盖NS_DESIGNATED_INITIALIZER
超类方法(在这种情况下为NSObject
's init:
)——我们过去常常NS_UNAVAILABLE
将此方法标记为不需要的。或者您可以覆盖它以使用默认参数调用指定的初始化程序。
回答by larva
Designated initializers define how we structure our initializers when subclassing; they are the “canonical initializer” for your class. It guaranteed to be reliable regardless of which designated initializer in the superclass chain you call, and will always go from furthest ancestor to furthest descendant.
指定的初始化器定义了我们在子类化时如何构造初始化器;它们是您的类的“规范初始化器”。无论您调用超类链中的哪个指定初始化程序,它都保证是可靠的,并且总是从最远的祖先到最远的后代。
A designated initializer does not define what initializer you should use when creating an object. It's very explained in https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns.
指定的初始化程序没有定义在创建对象时应该使用什么初始化程序。在https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns 中有很好的解释。