班级FooClass
应该只允许通过其sharedInstance
进行互动。我试图通过不允许任何人访问init()
的{{1}}来防止滥用。
我尝试过几种不同的方法,但都没有效果:
使用私人关键字:
FooClass
使用@available:
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()
我也试过使用内部,但仍然没有运气。
更新
如果将第一个版本移动到自己的文件中,则第一个版本可以工作,但是该类的ObjC版本仍然允许调用init。有什么想法吗?
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()
答案 0 :(得分:5)
This answer addresses Swift 2. In Swift 3 it looks like the access level of a method is correctly imported from Swift to Objective-C and does not need to be marked as NS_UNAVAILABLE
in order to disallow it from being available. Of course, there is no new
method in Swift so that will still need to be marked as NS_UNAVAILABLE
to maintain the singleton properly.
Your first approach will work as long as the class is put in its own file. The access control keyword private
means that the defined feature will only be available within the containing file.
However, as you said, using the Swift class in Objective-C will remove the protection that private
gives you. I believe that's because anything marked private
will not have an entry in the imported header file generated by the compiler. Thus the init
function inherited from NSObject
is available because it isn't overridden.
The solution I found is to create another header file that explicitly declares an init
function that can't be called.
Swift class:
@objc(FooClass)
class FooClass: NSObject {
// singleton
static let sharedInstance = FooClass()
let value: String
private override init() {
self.value = "asdf"
}
}
Objective-C header:
@interface FooClass (SharedInstance)
+ (instancetype) new NS_UNAVAILABLE;
- (instancetype) init NS_UNAVAILABLE;
@end
You have to also block new
because if you don't then an instance of the class could be created through it.
Testing:
FooClass* foo = [FooClass sharedInstance]; // All good here
FooClass* foo2 = [[FooClass alloc] init]; // 'init' is unavailable
FooClass* foo3 = [FooClass new]; // 'new' is unavailable
I have a rudimentary example project here: SharedInstance project git
答案 1 :(得分:3)
您可以使用@available()
注释:
@available(*, unavailable, message: "Use __your_init__ instead")
override init() {
fatalError("init() has not been implemented")
}