该类FooClass应仅允许通过进行交互sharedInstance。我试图防止滥用不容许任何人访问init()的FooClass。
我尝试了几种不同的方法,但是没有用:
使用私人关键字:
class FooClass: NSObject {
// singleton
static let sharedInstance = FooClass()
let value: String
private override init() {
self.value = "asdf"
}
}
// this should be a compile error, but it is not
let foo = FooClass()
Run Code Online (Sandbox Code Playgroud)
使用@available:
class FooClass: NSObject {
// singleton
// COMPILE ERROR - "init is unavailable. use sharedInstance"
static let sharedInstance = FooClass()
let value: String
@available(*, unavailable, message="use sharedInstance")
override init() {
self.value = "asdf"
}
}
// COMPILE ERROR - as it should be
let foo = FooClass()
Run Code Online (Sandbox Code Playgroud)
我也尝试使用内部,但仍然没有运气。
更新
如果将第一个版本移到其自己的文件中,则可以使用第一个版本,但是该类的ObjC版本仍允许调用init。有任何想法吗?
SWIFT_CLASS("_TtC11SwiftToObjC8FooClass")
@interface FooClass : NSObject
+ (FooClass * __nonnull)sharedInstance;
@property (nonatomic, readonly, copy) NSString * __nonnull value;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
Run Code Online (Sandbox Code Playgroud)
这个答案针对Swift2。在Swift 3中,方法的访问级别似乎已从Swift正确导入到Objective-C,并且不需要将其标记为NS_UNAVAILABLE,以禁止其可用。当然,newSwift中没有方法,因此仍然需要标记为NS_UNAVAILABLE正确维护单例。
只要将类放在自己的文件中,您的第一种方法就可以工作。访问控制关键字private意味着定义的功能将仅在包含文件中可用。
但是,正如您所说,在Objective-C中使用Swift类将删除private为您提供的保护。我相信这是因为任何标记的东西private在编译器生成的导入头文件中都没有条目。因此,init继承自的功能NSObject是可用的,因为它不会被覆盖。
我发现的解决方案是创建另一个头文件,该头文件显式声明一个init无法调用的函数。
迅捷类:
@objc(FooClass)
class FooClass: NSObject {
// singleton
static let sharedInstance = FooClass()
let value: String
private override init() {
self.value = "asdf"
}
}
Run Code Online (Sandbox Code Playgroud)
Objective-C标头:
@interface FooClass (SharedInstance)
+ (instancetype) new NS_UNAVAILABLE;
- (instancetype) init NS_UNAVAILABLE;
@end
Run Code Online (Sandbox Code Playgroud)
您还必须阻止,new因为如果不这样做,则可以通过该类创建该类的实例。
测试:
FooClass* foo = [FooClass sharedInstance]; // All good here
FooClass* foo2 = [[FooClass alloc] init]; // 'init' is unavailable
FooClass* foo3 = [FooClass new]; // 'new' is unavailable
Run Code Online (Sandbox Code Playgroud)
我在这里有一个简单的示例项目:SharedInstance项目git
您可以使用@available()注释:
@available(*, unavailable, message: "Use __your_init__ instead")
override init() {
fatalError("init() has not been implemented")
}
Run Code Online (Sandbox Code Playgroud)