2015-04-10 15 views
6

Đây là một chút của một banger đầu (đối với tôi). Về cơ bản tôi muốn có 2 single khác nhau kế thừa từ cùng một lớp. Trong một trong hai tôi muốn sử dụng một lớp nhất định mà bản thân nó có nguồn gốc. Vì vậy, tôi có Utility và cả hai AUtil:UtilityBUtil:Utility. Và Singleton được sử dụng như ASingleton sử dụng AUtility trong dạ dày và B tương ứng. Tôi đã thất bại trên tất cả các biên giới. Nỗ lực cuối cùng là một mô hình nhà máy mà chỉ đơn giản có Swift 1.2 để segfault:Tạo ra một singleton chung

protocol Initializable { init() } 
class A:Initializable { 
    var x = "A" 
    required init() {} 
} 
class B:Initializable { 
    var x = "B" 
    required init() {} 
} 

class C { 
    let t:Initializable 
    init(t:Initializable) { 
    self.t = t 
    println(t) 
    } 
    func factory() { 
    println(t.dynamicType()) 
    } 
} 

Như đã nói tôi cũng đã cố gắng để làm cho các mô hình sau generic:

private let _SingletonSharedInstance = StaticClass() 

class StaticClass { 
    class var sharedInstance : StaticClass { 
    return _SingletonSharedInstance 
    } 
} 

let s = StaticClass.sharedInstance 

(Cái này không phải là chung chung như bạn Nhưng tất cả những nỗ lực của tôi đều thất bại và vì vậy tôi cho thấy điểm xuất phát của mình.)

Dù sao tôi dường như bị mất giữa doom và cái chết.

Trả lời

4

Bạn có ý nghĩa như thế này không?

protocol Initializable: class { init() } 

private var instances = [String: Initializable]() 

func singletonInstance<T: Initializable>(_ ty: T.Type = T.self) -> T { 
    let name = NSStringFromClass(ty) 
    if let o = (instances[name] as? T) { 
     return o 
    } 
    let o = ty() 
    instances[name] = o 
    return o 
} 

Mặt bên sử dụng của nó, ví dụ.

class Foo: Initializable { required init() {} } 
class Bar: Initializable { required init() {} } 

let foo1 = singletonInstance() as Foo // or `singletonInstance(Foo.self)` 
let foo2 = singletonInstance() as Foo 
assert(foo1 === foo2) 

let bar1 = singletonInstance() as Bar 
let bar2 = singletonInstance() as Bar 
assert(bar1 === bar2) 

(tôi đã thử nghiệm các mã trên và đã nhận nó làm việc trong Swift 1.2.)

+0

Đ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. –

+0

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. –

+0

@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

3

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: 4khi bạn gọi cho bộ thu phát. Nhưng đây là lỗi beta đã được xác nhận.

+1

'setInstnace' có thể là lỗi đánh máy bạn có thể sửa :-) –

+0

Tôi sử dụng mã của bạn trên một lớp chung để quản lý bộ nhớ cache. Hoạt động tuyệt vời! –

+0

@CanATAC mã này hơi lỗi thời. Nếu bạn quan tâm bạn có thể kiểm tra phiên bản cuối cùng của tôi trên GitHub: https://github.com/DevAndArtist/SingletonGenerator Vui vì tôi có thể giúp một ai đó. – DevAndArtist

Các vấn đề liên quan