Lấy cảm hứng từ thực hiện findalls, tôi xây dựng máy phát điện singleton của riêng tôi, mà là mạnh hơn một chút.
Bạn có thể tạo một singleton của bất kỳ loại Class hoặc cấu trúc nào trong Swift. Điều duy nhất bạn phải làm là thực hiện một trong hai giao thức khác nhau với kiểu của bạn và sử dụng Swift 2.0 hoặc mới hơn.
public protocol SingletonType { init() }
private var singletonInstances = [String: SingletonType]()
extension SingletonType {
// this will crash Xcode atm. it's a Swift 2.0 beta bug. Bug-ID: 21850697
public static var singleton: Self { return singleton { $0 } }
public static func singleton(setter: (_: Self) -> Self) -> Self {
guard let instance = singletonInstances["\(self)"] as? Self else {
return setInstance(self.init(), withSetter: setter, overridable: true)
}
return setInstance(instance, withSetter: setter, overridable: false)
}
private static func setInstance(var instance: Self, withSetter setter: (_: Self) -> Self, overridable: Bool) -> Self {
instance = restoreInstanceIfNeeded(instance1: instance, instance2: setter(instance), overridable: overridable)
singletonInstances["\(self)"] = instance
return instance
}
private static func restoreInstanceIfNeeded(instance1 i1: Self, instance2 i2: Self, overridable: Bool) -> Self {
// will work if the bug in Swift 2.0 beta is fixed !!! Bug-ID: 21850627
guard i1.dynamicType is AnyClass else { return i2 }
return ((i1 as! AnyObject) !== (i2 as! AnyObject)) && !overridable ? i1 : i2
}
}
Điều này có thể hơi đáng sợ nhưng đừng sợ mã này. Hàm chung trong phần mở rộng giao thức sẽ tạo hai điểm truy cập cho bạn. Ví dụ, bạn sẽ có thể viết mã như bây giờ điều này:
// extend your type: as an example I will extend 'Int' here
extension Int : SingletonType {} // nothing else to do, because Int already has an 'init()' initializer by default
// let the magic happen
Int.singleton // this will generate a singleton Int with 0 as default value
Int.singleton { (_) -> Int in 100 } // should set your Int singleton to 100
Int.singleton { $0 - 55 } // your singleton should be 45 now
// I need to mention that Xcode will produce the setter like this and trow an error
Int.singleton { (yourCustomInstanceName) -> Self in // replace 'Self' with 'Int' and you should be fine
return yourCustomInstanceName
}
// btw. we just ignored the return value everywhere
print(Int.singleton) // will print 45 here
var singleton2 = Int.singleton { $0 + 5 }
singleton2 += 10
print(Int.singleton) // should print 50, because 'singleton2' is just a copy of an Int value type
class A : SingletonType {
var name = "no name"
required init() {}
}
A.singleton { $0; let i = A(); i.name = "hello world"; return i } // custom init on first singleton call for type A
print(A.singleton.name)
print(A.singleton { $0.name = "A"; return $0 }.name)
print(A.singleton.name)
// should print "hello world" and twice the string "A"
Nếu bạn có bất kỳ ý tưởng làm thế nào để tăng cường mã này và làm cho nó thậm chí còn an toàn hơn, xin vui lòng cho tôi biết. Tôi sẽ sớm đẩy mã này vào GitHub (Giấy phép MIT) để mọi người có thể hưởng lợi từ nó.
CẬP NHẬT: Tôi đã sửa đổi mã một chút để bây giờ bạn có thể vượt qua một thể hiện khởi tạo tùy chỉnh của một lớp có chức năng setter khi được gọi lần đầu tiên.
CẬP NHẬT 2: Tôi đã xóa giao thức ClassInstance và sửa đổi chức năng khôi phục riêng tư. Giao thức Instance
giờ đây được gọi là SingletonType
. Hàm setter không còn tùy chọn nữa. Ngay bây giờ Xcode 7 beta 3 sẽ bị lỗi và cung cấp lỗiillegal instruction: 4
khi bạn gọi cho bộ thu phát. Nhưng đây là lỗi beta đã được xác nhận.
Điều đó có vẻ đầy hứa hẹn. Cảm ơn :-) Tôi sẽ xem nếu tôi nhận được điều này làm việc ngày hôm nay. –
Có lý do nào để sử dụng 'flatMap' không? 'if let o = (instance [name] as? T)' dường như cũng hoạt động. Tôi đã phải tìm ra phương pháp mới vì nó mới với một trong số 1.2 beta mới nhất. –
@ThomasKilian Xin lỗi, bạn đã đúng.Tôi đã không biết rằng 'if let' có thể mở ra một giá trị tùy chọn gấp đôi,' Initializable ?? 'ở đó. Cảm ơn! – findall