好吧,这无疑是一个最佳实践问题,但我想说得对,所以希望有人可以启发我:
场景非常标准,但有一个转折点:
我在我编写的框架中有一个类,它直接从NSObject
继承。它有一个带有很多参数的指定初始值设定项,其中大部分都是nonnull
。由于该东西是框架的一部分,我明确使用NS_DESIGNATED_INITIALIZER
宏(我不会总是在较小的个人应用程序中执行)。
问题是这导致XCode警告我也覆盖init
,即超类的指定初始化程序。但另外它要求我从中调用我的指定的initalizer,这是我无法做到的,因为我的参数缺乏有意义的默认值。
我真的不想在"小" init
,我更愿意返回nil
。
为了摆脱警告,我在我班级的扩展程序中添加了init
作为第二个指定的initalizer,如下所示:
@interface MyClassName ()
// some other stuff not relevant`
-(nullable instancetype)init NS_DESIGNATED_INITIALIZER;
@end
现在我可以安全地return nil;
覆盖init
方法,就像我想要的那样。
这意味着我的文档(我使用appledoc)和扩展XCode的代码完成不会告诉使用我的框架的人init
实际上也是指定的初始化程序(所以他们赢了&# 39;意外地使用它),但它仍然存在(例如,在单元测试中,这可能会派上用场)。
我的问题是:除了实际在生产中使用它的人之外,还有任何危险吗,之后快乐地发送消息给nil而没有意识到?这是少数几个在init中抛出异常的情况之一吗?
答案 0 :(得分:7)
而不是仅仅从nil
返回init
(并且可能添加评论说你不应该调用它) - 你应该将其标记为不可用。
如果有人试图拨打NSObject
而不是您指定的初始用户,那么这不仅会解除您未覆盖init
指定初始化工具的警告 - 它还会产生编译时错误。< / p>
为此,您可以使用NS_UNAVAILABLE
宏,也可以使用this answer所示的不可用__attribute__
。使用__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