好吧,这确实是一个最佳实践问题,但我想把它做对,所以希望有人能启发我:
场景非常标准,但有一个转折点:
我编写的框架中有一个类直接继承自 NSObject
。它有一个带有相当多参数的指定初始化器,其中大部分是 nonnull
。由于它是框架的一部分,我明确地使用了 NS_DESIGNATED_INITIALIZER
宏(我并不总是在较小的个人应用程序中这样做)。
问题是这导致 XCode 警告我也覆盖 init
,即父类(super class)的指定初始化程序。但另外它要求我从它调用我的 指定的初始化器,我不能这样做,因为我只是缺少有意义的参数默认值。
我真的不想在“小”init
中抛出异常,我更愿意返回 nil
。
为了消除警告,我在类的扩展中添加了 init
作为第二个指定的初始化程序,如下所示:
@interface MyClassName ()
// some other stuff not relevant`
-(nullable instancetype)init NS_DESIGNATED_INITIALIZER;
@end
现在我可以像我想要的那样在覆盖的 init
方法中安全地 return nil;
。
这意味着我的文档(我正在使用 appledoc)和扩展 XCode 的代码完成不会告诉使用我的框架的人 init
实际上也是一个指定的初始化程序(所以他们不会意外使用它) , 但它仍然存在(例如,在单元测试中,这可能会派上用场)。
我的问题是:除了有人实际在生产中使用它之外,这是否有任何危险,然后在没有意识到的情况下愉快地向 nil 发送消息?这会是在 init 中抛出异常更好的少数情况之一吗?
最佳答案
而不是仅仅从 init
返回 nil
(并且可能添加一条评论说你不应该调用它)——你应该将它标记为不可用。
这不仅会消除关于你没有覆盖 NSObject
的指定初始化器的警告——如果有人试图调用 init
,它还会产生一个编译时错误您指定的初始化程序。
为此,您可以使用NS_UNAVAILABLE
宏,或使用不可用的__attribute__
,如this answer 所示。 .使用 __attribute__
的优点是您可以指定编译器将呈现给用户的消息。
例如:
@interface Foo : NSObject
-(instancetype) init __attribute__((unavailable("You cannot create a foo instance through init - please use initWithBar:")));
-(instancetype) initWithBar:(Bar*)bar NS_DESIGNATED_INITIALIZER;
@end
...
Foo* fooA = [[Foo alloc] init]; // ERROR: 'init' is unavailable: You cannot create a foo instance through init - please use initWithBar:
Foo* fooB = [[Foo alloc] initWithBar:[[Bar alloc] init]]; // No error
关于ios - 如何使用 NS_DESIGNATED_INITIALIZER 并覆盖 init?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36574662/