swift - स्विफ्ट में एक dispatch_once सिंगलटन मॉडल का उपयोग करना




singleton (19)

1.2 से ऊपर स्विफ्ट में सबसे अच्छा तरीका एक लाइन सिंगलटन है, जैसा कि -

class Shared: NSObject {

    static let sharedInstance = Shared()

    private override init() { }
}

इस दृष्टिकोण के बारे में अधिक जानकारी के लिए आप इस link पर जा सकते हैं।

मैं स्विफ्ट में उपयोग के लिए एक उपयुक्त सिंगलटन मॉडल तैयार करने की कोशिश कर रहा हूं। अब तक, मैं एक गैर थ्रेड सुरक्षित मॉडल के रूप में काम करने में सक्षम हूं:

class var sharedInstance:TPScopeManager {
    get {
        struct Static {
            static var instance : TPScopeManager? = nil
        }

        if !Static.instance {
            Static.instance = TPScopeManager()
        }

        return Static.instance!
    }
}

स्टेटिक स्ट्रक्चर में सिंगलटन इंस्टेंस को लपेटने से एक ऐसे इंस्टेंस को अनुमति मिलनी चाहिए जो जटिल नामकरण योजनाओं के बिना सिंगलटन इंस्टेंस के साथ टकराव न करे, और इसे चीजों को काफी निजी बनाना चाहिए। जाहिर है, हालांकि, यह मॉडल थ्रेड सुरक्षित नहीं है, इसलिए मैंने पूरी चीज़ पर dispatch_once जोड़ने की कोशिश की:

class var sharedInstance:TPScopeManager {
    get {
        struct Static {
            static var instance : TPScopeManager? = nil
            static var token : dispatch_once_t = 0
        }

        dispatch_once(Static.token) { Static.instance = TPScopeManager() }

        return Static.instance!
    }
}

लेकिन मुझे dispatch_once लाइन पर एक कंपाइलर त्रुटि मिलती है:

'()' टाइप करने के लिए अभिव्यक्ति के प्रकार 'शून्य' को परिवर्तित नहीं कर सकता

मैंने वाक्यविन्यास के कई अलग-अलग प्रकारों की कोशिश की है, लेकिन वे सभी एक ही परिणाम प्रतीत होते हैं:

dispatch_once(Static.token, { Static.instance = TPScopeManager() })

स्विफ्ट का उपयोग कर dispatch_once का उचित उपयोग क्या है? मैंने शुरू में सोचा था कि समस्या त्रुटि संदेश में () कारण ब्लॉक के साथ थी, लेकिन जितना अधिक मैं इसे देखता हूं, उतना ही मुझे लगता है कि यह dispatch_once_t सही तरीके से परिभाषित करने का मामला हो सकता है।


अतीत में सिंगलटन का एहसास करने के लिए स्विफ्ट, तीन तरीकों से अधिक कुछ नहीं है: वैश्विक चर, आंतरिक चर और dispatch_once तरीके।

यहां दो अच्छे सिंगलटन हैं। (ध्यान दें: इससे कोई फर्क नहीं पड़ता कि किस तरह के लेखन को निजीकरण की init () विधि पर ध्यान देना होगा। क्योंकि स्विफ्ट में, सभी ऑब्जेक्ट का कन्स्ट्रक्टर डिफ़ॉल्ट सार्वजनिक है, फिर से लिखने की जरूरत है init को निजी में बदल दिया जा सकता है ऑब्जेक्ट बनाने के लिए डिफ़ॉल्ट प्रारंभिक विधि द्वारा इस वर्ग '()' की अन्य ऑब्जेक्ट्स को रोकें।)

विधि 1:

class AppManager {
    private static let _sharedInstance = AppManager()

    class func getSharedInstance() -> AppManager {
       return _sharedInstance
    }

    private init() {} // Privatizing the init method
}

// How to use?
AppManager.getSharedInstance()

विधि 2:

class AppManager {
    static let sharedInstance = AppManager()

    private init() {} // Privatizing the init method
}

// How to use?
AppManager.sharedInstance

ऐप्पल के नमूना कोड को देखते हुए मैं इस पैटर्न में आया था। मुझे यकीन नहीं है कि कैसे स्विफ्ट statics के साथ सौदा करता है, लेकिन यह सी # में धागा सुरक्षित होगा। मैं उद्देश्य-सी इंटरऑप के लिए संपत्ति और विधि दोनों शामिल करता हूं।

struct StaticRank {
    static let shared = RankMapping()
}

class func sharedInstance() -> RankMapping {
    return StaticRank.shared
}

class var shared:RankMapping {
    return StaticRank.shared
}

ऐसा करने का एक बेहतर तरीका है। आप कक्षा की गिरावट के ऊपर अपनी कक्षा में एक वैश्विक चर घोषित कर सकते हैं

var tpScopeManagerSharedInstance = TPScopeManager()

यह स्विफ्ट में डिफ़ॉल्ट रूप से डिफ़ॉल्ट रूप से आपके डिफ़ॉल्ट init या जो भी init और वैश्विक चर dispatch_once कहते हैं। फिर आप जिस भी कक्षा में संदर्भ प्राप्त करना चाहते हैं, आप बस यह करें:

var refrence = tpScopeManagerSharedInstance
// or you can just access properties and call methods directly
tpScopeManagerSharedInstance.someMethod()

तो मूल रूप से आप साझा आवृत्ति कोड के पूरे ब्लॉक से छुटकारा पा सकते हैं।


डेविड के कार्यान्वयन को देखने के बाद, ऐसा लगता है कि सिंगलटन क्लास फ़ंक्शन इंस्टेंस मोड की आवश्यकता नहीं है क्योंकि let एक साझा इंस्टेंस क्लास विधि के समान ही काम कर रहा है। आपको बस इतना करना है कि इसे वैश्विक स्थिरता के रूप में घोषित करें और यह होगा।

let gScopeManagerSharedInstance = ScopeManager()

class ScopeManager {
 // No need for a class method to return the shared instance. Use the gScopeManagerSharedInstance directly. 
}

थ्रेड सुरक्षित क्षमताओं के साथ यह सबसे आसान है। कोई अन्य धागा उसी सिंगलटन ऑब्जेक्ट तक पहुंच सकता है, भले ही वे चाहते हों। स्विफ्ट 3/4

struct DataService {

    private static var _instance : DataService?

    private init() {}   //cannot initialise from outer class

    public static var instance : DataService {
        get {
            if _instance == nil {
                DispatchQueue.global().sync(flags: .barrier) {
                    if _instance == nil {
                        _instance = DataService()
                    }
                }
            }
            return _instance!
        }
    }
}

मैं एक एनम का सुझाव दूंगा, जैसे आप जावा में उपयोग करेंगे, उदाहरण के लिए:

enum SharedTPScopeManager: TPScopeManager {
  case Singleton
}

मैं बस इसके साथ आया, लेकिन मुझे अपने सिंगलटन को विरासत की अनुमति देने की आवश्यकता थी, और इन समाधानों में से कोई भी वास्तव में इसकी अनुमति नहीं देता था।

तो मैं इसके साथ आया:

public class Singleton {
  private static var sharedInstanceVar = Singleton()

  public class func sharedInstance()->Singleton {
    return sharedInstanceVar
  }
}


public class SubSingleton: Singleton {

  private static var sharedInstanceToken:dispatch_once_t = 0

  public class override func sharedInstance()->SubSingleton {
    dispatch_once(&sharedInstanceToken){
      sharedInstanceVar = SubSingleton()
    }
    return sharedInstanceVar as! SubSingleton
  }
}
  • इस तरह सिंगलटन। शेरडेंस () पहले करते समय यह सिंगलटन के उदाहरण को वापस कर देगा
  • SubSingleton.sharedInstance () पहले करते समय यह सबसिंगलेटन के उदाहरण को वापस कर देगा।
  • यदि उपर्युक्त किया जाता है, तो SubSingleton.sharedInstance () सिंगलटन सत्य है और एक ही उदाहरण का उपयोग किया जाता है।

इस पहले गंदे दृष्टिकोण के साथ मुद्दा यह है कि मैं गारंटी नहीं दे सकता कि subclasses dispatch_once_t को लागू करेंगे और यह सुनिश्चित कर लेंगे कि ShareInstanceVar केवल प्रति कक्षा में संशोधित है ...

मैं इसे और परिशोधित करने की कोशिश करूंगा, लेकिन यह देखना दिलचस्प होगा कि किसी के खिलाफ इसके खिलाफ मजबूत भावनाएं हैं (इस तथ्य के अलावा कि यह वर्बोज़ है और इसे मैन्युअल रूप से अपडेट करने की आवश्यकता है)।


यह मेरा कार्यान्वयन है। यह प्रोग्रामर को एक नया उदाहरण बनाने से रोकता है:

let TEST = Test()

class Test {

    private init() {
        // This is a private (!) constructor
    }
}

संक्षेप में,

class Manager {
    static let sharedInstance = Manager()
    private init() {}
}

आप here पढ़ना चाह सकते हैं

ग्लोबल वेरिएबल (स्ट्रक्चर और एनम्स के स्थिर सदस्यों के लिए) के लिए आलसी प्रारंभकर्ता पहली बार चलाया जाता है जब वैश्विक एक्सेस किया जाता है, और यह सुनिश्चित करने के लिए कि प्रारंभिकता परमाणु है, dispatch_once रूप में लॉन्च किया गया है।


स्विफ्ट 1.2 या बाद में कक्षाओं में स्थिर चर / स्थिरांक का समर्थन करता है। तो आप केवल स्थिर स्थिरता का उपयोग कर सकते हैं:

class MySingleton {

    static let sharedMySingleton = MySingleton()

    private init() {
        // ...
    }
}

स्विफ्ट में कार्यान्वयन का मेरा तरीका ...

ConfigurationManager.swift

import Foundation

    let ConfigurationManagerSharedInstance = ConfigurationManager()
 class ConfigurationManager : NSObject {
    var globalDic: NSMutableDictionary = NSMutableDictionary()

class var sharedInstance:ConfigurationManager {
    return ConfigurationManagerSharedInstance

}

init() {

    super.init()

    println ("Config Init been Initiated, this will be called only onece irrespective of many calls")   

}

नीचे दिए गए एप्लिकेशन की किसी भी स्क्रीन से globalDic तक पहुंचें।

पढ़ें:

 println(ConfigurationManager.sharedInstance.globalDic)  

लिखना:

 ConfigurationManager.sharedInstance.globalDic = tmpDic // tmpDict is any value that to be shared among the application

ऐप्पल प्रलेखन के अनुसार , इसे कई बार दोहराया गया है कि स्विफ्ट में ऐसा करने का सबसे आसान तरीका एक स्थिर प्रकार की संपत्ति के साथ है:

class Singleton {
    static let sharedInstance = Singleton()
}

हालांकि, यदि आप एक साधारण कन्स्ट्रक्टर कॉल से अतिरिक्त सेटअप करने का कोई तरीका ढूंढ रहे हैं, तो गुप्त तुरंत उपयोग किए जाने वाले बंद का उपयोग करना है:

class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code
        return instance
    }()
}

यह थ्रेड-सुरक्षित होने और आलसी रूप से केवल एक बार शुरू होने की गारंटी है।


टीएल; डॉ: यदि आप पिछले संस्करणों का समर्थन करने की आवश्यकता है तो स्विफ्ट 1.2 या ऊपर और नेस्टेड स्ट्रक्चर दृष्टिकोण का उपयोग कर रहे हैं, तो कक्षा निरंतर दृष्टिकोण का उपयोग करें।

स्विफ्ट के साथ अपने अनुभव से आलसी पैटर्न को लागू करने के तीन दृष्टिकोण हैं जो आलसी प्रारंभिकरण और थ्रेड सुरक्षा का समर्थन करते हैं।

कक्षा निरंतर

class Singleton  {
   static let sharedInstance = Singleton()
}

यह दृष्टिकोण आलसी प्रारंभिकरण का समर्थन करता है क्योंकि स्विफ्ट आलसी क्लास स्थिरांक (और चर) को प्रारंभ करता है, और थ्रेड की परिभाषा से थ्रेड सुरक्षित है। अब यह एक सिंगलटन को चालू करने के लिए आधिकारिक तौर पर अनुशंसित तरीका है।

स्विफ्ट 1.2 में कक्षा स्थिरांक पेश किए गए थे। यदि आपको स्विफ्ट के पहले संस्करण का समर्थन करने की आवश्यकता है, तो नीचे नेस्टेड स्ट्रक्चर दृष्टिकोण या वैश्विक स्थिरता का उपयोग करें।

नेस्टेड संरचना

class Singleton {
    class var sharedInstance: Singleton {
        struct Static {
            static let instance: Singleton = Singleton()
        }
        return Static.instance
    }
}

यहां हम एक कक्षा निरंतर के रूप में एक नेस्टेड संरचना के स्थिर स्थिरांक का उपयोग कर रहे हैं। स्विफ्ट 1.1 और इससे पहले में स्थिर वर्ग स्थिरांक की कमी के लिए यह एक कामकाज है, और स्थिर स्थिर स्थिरांक और कार्यों में चर के अभाव के लिए अभी भी कामकाज के रूप में काम करता है।

dispatch_once

स्विफ्ट के लिए पोर्ट किया गया पारंपरिक उद्देश्य-सी दृष्टिकोण। मुझे काफी यकीन है कि नेस्टेड स्ट्रक्चर दृष्टिकोण पर कोई फायदा नहीं है लेकिन मैं इसे यहां भी डाल रहा हूं क्योंकि मुझे सिंटैक्स में अंतर दिलचस्प लगता है।

class Singleton {
    class var sharedInstance: Singleton {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: Singleton? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = Singleton()
        }
        return Static.instance!
    }
}

यूनिट परीक्षणों के लिए यह GitHub परियोजना देखें।


पहला समाधान

let SocketManager = SocketManagerSingleton();

class SocketManagerSingleton {

}

बाद में आपके कोड में:

func someFunction() {        
    var socketManager = SocketManager        
}

दूसरा समाधान

func SocketManager() -> SocketManagerSingleton {
    return _SocketManager
}
let _SocketManager = SocketManagerSingleton();

class SocketManagerSingleton {

}

और बाद में आपके कोड में आप कम भ्रम के लिए ब्रेसिज़ रखने में सक्षम होंगे:

func someFunction() {        
    var socketManager = SocketManager()        
}

स्विफ्ट 1.2 और उससे आगे के लिए:

class Singleton  {
   static let sharedInstance = Singleton()
}

शुद्धता के सबूत के साथ (सभी क्रेडिट here जाते here ), सिंगलेट के लिए पिछले किसी भी तरीके का उपयोग करने के लिए अब कोई कारण नहीं है।

अद्यतन : अब आधिकारिक दस्तावेज़ों में वर्णित सिंगलटन को परिभाषित करने का आधिकारिक तरीका है!

static बनाम class का उपयोग करने पर चिंताओं के लिए। class चर उपलब्ध होने पर भी static होना चाहिए। सिंगलेट्स का वर्गीकरण नहीं किया जाता है क्योंकि इसके परिणामस्वरूप बेस सिंगलटन के कई उदाहरण होंगे। static का उपयोग करके इसे एक सुंदर, स्विफ्ट तरीके से लागू किया जाता है।

स्विफ्ट 1.0 और 1.1 के लिए:

स्विफ्ट में हालिया परिवर्तनों के साथ, ज्यादातर नए एक्सेस कंट्रोल विधियों के साथ, अब मैं सिंगलेट्स के लिए ग्लोबल वैरिएबल का उपयोग करने के क्लीनर तरीके की तरफ झुका रहा हूं।

private let _singletonInstance = SingletonClass()
class SingletonClass {
  class var sharedInstance: SingletonClass {
    return _singletonInstance
  }
}

जैसा कि here स्विफ्ट ब्लॉग आलेख में बताया गया here :

ग्लोबल वेरिएबल (स्ट्रक्चर और एनम्स के स्थिर सदस्यों के लिए) के लिए आलसी प्रारंभकर्ता पहली बार चलाया जाता है जब वैश्विक एक्सेस किया जाता है, और यह सुनिश्चित करने के लिए कि प्रारंभिकता परमाणु है, प्रेषण के रूप में लॉन्च किया गया है। यह आपके कोड में dispatch_once का उपयोग करने का एक शानदार तरीका सक्षम करता है: केवल प्रारंभिक के साथ एक वैश्विक चर घोषित करें और इसे निजी चिह्नित करें।

सिंगलटन बनाने का यह तरीका थ्रेड सुरक्षित, तेज़, आलसी है, और ओबीजेसी को भी मुफ्त में ब्रिज किया गया है।


मैं निम्नलिखित वाक्यविन्यास का सबसे पूरा उपयोग करता हूं:

public final class Singleton {    
    private class func sharedInstance() -> Singleton {
        struct Static {
            //Singleton instance.
            static let sharedInstance = Singleton()
        }
        return Static.sharedInstance
    }

    private init() { }

    class var instance: Singleton {
        return sharedInstance()
    }
}

यह स्विफ्ट 1.2 से 4 तक काम करता है, और कई गुण प्रदान करता है:

  1. उपयोगकर्ता को कार्यान्वयन को उपclass नहीं करने के लिए याद दिलाता है
  2. अतिरिक्त उदाहरणों के निर्माण से बचाता है
  3. आलसी सृजन और अद्वितीय तात्कालिकता सुनिश्चित करता है
  4. उदाहरण के रूप में उपयोग करने की इजाजत देकर वाक्यविन्यास (avoids ()) को छोटा करता है Singleton.instance

   func init() -> ClassA {
    struct Static {
        static var onceToken : dispatch_once_t = 0
        static var instance : ClassA? = nil
    }

    dispatch_once(&Static.onceToken) {
        Static.instance = ClassA()
    }

    return Static.instance!
}

private var sharedURLCacheForRequestsKey:Void?
extension URLCache{
public static func sharedURLCacheForRequests()->URLCache{
    var cache = objc_getAssociatedObject(OperationQueue.main, &sharedURLCacheForRequestsKey)
    if cache is URLCache {

    }else{
        cache = URLCache(memoryCapacity: 0, diskCapacity: 1*1024*1024*1024, diskPath: "sharedURLCacheForRequestsKey")
        objc_setAssociatedObject(OperationQueue.main, &sharedURLCacheForRequestsKey, cache, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

    }
    return cache as! URLCache
}}




dispatch