是否可以在Objective-C中将-init方法设为私有?

laj*_*jos 143 objective-c

我需要-init在Objective-C中隐藏(私有)我的类的方法.

我怎样才能做到这一点?

Jan*_*ano 333

NS_UNAVAILABLE

- (instancetype)init NS_UNAVAILABLE;
Run Code Online (Sandbox Code Playgroud)

这是不可用属性的简短版本.它首先出现在macOS 10.7iOS 5中.它在NSObjCRuntime.h中定义为#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE.

有一个版本只为Swift客户端禁用该方法,而不是ObjC代码:

- (instancetype)init NS_SWIFT_UNAVAILABLE;
Run Code Online (Sandbox Code Playgroud)

unavailable

unavailable属性添加到标头以在任何对init的调用时生成编译器错误.

-(instancetype) init __attribute__((unavailable("init not available")));  
Run Code Online (Sandbox Code Playgroud)

编译时错误

如果您没有理由,只需输入__attribute__((unavailable)),甚至__unavailable:

-(instancetype) __unavailable init;  
Run Code Online (Sandbox Code Playgroud)

doesNotRecognizeSelector:

使用doesNotRecognizeSelector:提出一个NSInvalidArgumentException."只要对象收到无法响应或转发的aSelector消息,运行时系统就会调用此方法."

- (instancetype) init {
    [self release];
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}
Run Code Online (Sandbox Code Playgroud)

NSAssert

使用NSAssert抛出NSInternalInconsistencyException并显示一条消息:

- (instancetype) init {
    [self release];
    NSAssert(false,@"unavailable, use initWithBlah: instead");
    return nil;
}
Run Code Online (Sandbox Code Playgroud)

raise:format:

使用raise:format:抛出自己的异常:

- (instancetype) init {
    [self release];
    [NSException raise:NSGenericException 
                format:@"Disabled. Use +[[%@ alloc] %@] instead",
                       NSStringFromClass([self class]),
                       NSStringFromSelector(@selector(initWithStateDictionary:))];
    return nil;
}
Run Code Online (Sandbox Code Playgroud)

[self release]是必要的,因为该对象已经被使用了alloc.使用ARC时,编译器会为您调用它.在任何情况下,当你打算故意停止执行时,不要担心.

objc_designated_initializer

如果您打算禁用init强制使用指定的初始值设定项,则有一个属性:

-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)

除非任何其他初始化方法在myOwnInit内部调用,否则会生成警告.细节将在下一个Xcode发布后采用现代Objective-C发布(我猜).


leh*_*058 101

Apple已开始在其头文件中使用以下内容来禁用init构造函数:

- (instancetype)init NS_UNAVAILABLE;
Run Code Online (Sandbox Code Playgroud)

这在Xcode中正确显示为编译器错误.具体来说,这是在他们的几个HealthKit头文件中设置的(HKUnit就是其中之一).

  • 你也可以做+(instancetype)new NS_UNAVAILABLE; (11认同)
  • 请注意,您仍然可以使用[MyObject new]实例化对象; (3认同)

Chr*_*son 87

与Smalltalk一样,Objective-C没有"私有"与"公共"方法的概念.任何消息都可以随时发送到任何对象.

你可以做的是抛出一个NSInternalInconsistencyExceptionif你的-init方法被调用:

- (id)init {
    [self release];
    @throw [NSException exceptionWithName:NSInternalInconsistencyException
                                   reason:@"-init is not a valid initializer for the class Foo"
                                 userInfo:nil];
    return nil;
}
Run Code Online (Sandbox Code Playgroud)

另一种选择 - 在实践中可能要好得多 - 就是尽可能-init为你的班级做一些明智的事情.

如果您尝试这样做是因为您试图"确保"使用单个对象,请不要打扰.具体地,不与打扰"覆盖+allocWithZone:,-init,-retain,-release"创建单身的方法.它几乎总是不必要的,只是增加了复杂性,没有真正的显着优势.

相反,只需编写代码,以便您的+sharedWhatever方法是访问单例的方法,并将其记录为在标题中获取单例实例的方法.在绝大多数情况下,这应该是你所需要的.

  • 是的,为了让编译器满意.否则,编译器可能会抱怨返回非void返回的方法没有返回. (5认同)
  • *"没有真正的重大优势"*.完全不真实.显着的优点是你想要强制**单身模式.如果您允许创建新实例,那么不熟悉API的开发人员可能会使用`alloc`和`init`并且他们的代码功能不正确,因为他们有正确的类,但是错误的实例.这是OO中*encapsulation*原则的本质.您隐藏API中的其他类不应该或访问的内容.你不仅要把所有东西都公之于众,还要期待人类跟踪这一切. (4认同)
  • 指望开发人员遵循模式并不是一个好主意.最好抛出异常,因此不同团队的开发人员不知道.我的私人概念会更好. (3认同)
  • 这里的回报真的有必要吗? (2认同)