स्विफ्ट में एक डिस्पैच_ऑनस सिंगलटन मॉडल का उपयोग करना


575

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

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सही ढंग से परिभाषित होने की बात हो सकती है ।


3
मैं उस सभी स्टैटिक कोड को हटा दूंगा और @lazy initializer के साथ आसानी से प्रॉपर्टी का उपयोग करूंगा।
सुल्तान

1
मेरा मतलब यही था। दुर्भाग्य से हमारे पास अभी भी इंटर्नल के बारे में पर्याप्त जानकारी नहीं है। हालांकि, IMHO के किसी भी कार्यान्वयन @lazyथ्रेड सुरक्षित होना चाहिए।
सुल्तान

1
और इस तरह से कॉलर्स की भविष्यवाणी के कार्यान्वयन को उजागर नहीं करने का भी फायदा है।
डेविड बेरी

1
यह भी नहीं लगता है कि आपके पास @lazy वर्ग चर हो सकते हैं।
डेविड बेरी

सावधान रहे! इस दृष्टिकोण के साथ ध्यान देने योग्य दो बातें। सबसे पहले, इस से विरासत में आने वाले किसी भी वर्ग को साझा संपत्ति संपत्ति को ओवरराइड करना होगा। Static.instance = TPScopeManager()उदाहरण प्रकार को बल देता है। यदि आप Static.instance = self()किसी आवश्यक इनिशियलाइज़र के साथ कुछ का उपयोग करते हैं , तो उपयुक्त प्रकार वर्ग उत्पन्न किया जाएगा। फिर भी, और यह ध्यान देने योग्य बात है, केवल एक बार पदानुक्रम में सभी उदाहरणों के लिए! आरंभ करने के लिए पहला प्रकार सभी उदाहरणों के लिए निर्धारित प्रकार है। मुझे नहीं लगता कि ऑब्जेक्टिव-सी ने ऐसा ही व्यवहार किया है।
शॉन वुडवर्ड

जवाबों:


713

tl; डॉ: उपयोग वर्ग निरंतर दृष्टिकोण आप स्विफ्ट 1.2 या इसके बाद के संस्करण और प्रयोग कर रहे हैं नेस्टेड struct दृष्टिकोण अगर आप पुराने संस्करणों को समर्थन की जरूरत है।

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

कक्षा स्थिर

class Singleton  {
   static let sharedInstance = Singleton()
}

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

क्लास कॉन्स्टेंट्स को स्विफ्ट 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 परियोजना को देखें ।


13
"थ्रेड ऑफ़ लेट के द्वारा सुरक्षित धागा" - यह कहीं भी कहा गया है? मैं प्रलेखन में इसका उल्लेख नहीं कर सकता।
jtbandes

4
@jtbandes कॉन्स्टेंट मेरे द्वारा जानी जाने वाली सभी भाषाओं में सुरक्षित हैं।
hpique

2
@ मान लें कि आप अंतिम दृष्टिकोण के बारे में बात कर रहे हैं। मैं अपने आप को उद्धृत करता हूं: "मैं कहूंगा कि इस दृष्टिकोण का उपयोग करना अब आवश्यक नहीं है, लेकिन मैं इसे वैसे भी यहां डाल रहा हूं क्योंकि मुझे वाक्यविन्यास में अंतर दिलचस्प लगता है।"
hpique

5
किसी एक की गारंटी देने के लिए initभी घोषित किया जाना चाहिए privateऔर ऐप के जीवनकाल में ऑब्जेक्ट का केवल एक ही उदाहरण मौजूद होगा?
एंड्रयू

5
"क्लास स्थिरांक" दृष्टिकोण में, मैं सुझाव दूंगा कि (ए) वर्ग को घोषित करने के लिए finalआप इसे उप-वर्ग नहीं बनाते हैं ; और (बी) initविधि को घोषित करने के लिए privateताकि आप गलती से किसी अन्य उदाहरण को तुरंत कहीं न दें।
रोब

175

चूँकि Apple ने अब स्पष्ट किया है कि स्टैटिक स्ट्रक्चर वैरिएबल को आलसी और लिपटे हुए दोनों प्रकार से इनिशियलाइज़ किया जाता है dispatch_once(पोस्ट के अंत में नोट देखें), मुझे लगता है कि मेरा अंतिम समाधान होने जा रहा है:

class WithSingleton {
    class var sharedInstance: WithSingleton {
        struct Singleton {
            static let instance = WithSingleton()
        }

        return Singleton.instance
    }
}

यह स्थैतिक संरचना तत्वों के स्वत: आलसी, थ्रेड-सेफ इनिशियलाइज़ेशन का लाभ उठाता है, उपभोक्ता से वास्तविक कार्यान्वयन को सुरक्षित रूप से छुपाता है, सब कुछ सुव्यवस्थित रूप से पठनीयता के लिए संकलित रखता है, और एक दृश्यमान वैश्विक चर को समाप्त करता है।

Apple ने स्पष्ट किया है कि आलसी इनिशियलाइज़र थ्रेड-सेफ़ है, इसलिए इसके लिए dispatch_onceया समान सुरक्षा की कोई आवश्यकता नहीं है

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

से यहाँ


1
पुष्टि करने के लिए: वैश्विक चरों में आलसी, थ्रेड-सेफ इनिशियलाइज़ेशन है, लेकिन क्लास वैरिएबल नहीं हैं। सही?
बिल

14
मैं जोड़ूंगा कि एक अच्छा अभ्यास इनिशियलाइज़र को निजी घोषित करने के लिए होगा: private init() {}इस तथ्य को और अधिक लागू करने के लिए कि इस वर्ग का बाहरी रूप से त्वरित रूप से तात्पर्य नहीं है।
पास्कल बॉर्क

1
तो स्टेटिक स्ट्रक्चर वर्जन इनिशियलाइज़ेशन आलसी और थ्रेड सेफ है, क्या होगा अगर वह स्टैटिक स्ट्रक्चर वर्जन मल्टीटन के लिए डिक्शनरी है, तो हमें प्रत्येक एक्सेस के लिए इसे मैन्युअल रूप से / क्यू कॉल को सिंक्रोनाइज़ करना होगा, है ना?

यदि मैं आपके प्रश्न को सही ढंग से समझता हूं, तो शब्दकोश और सरणी एक्सेस स्वाभाविक रूप से थ्रेड-सुरक्षित नहीं हैं, इसलिए आपको थ्रेड सिंक्रोनाइज़ेशन के कुछ रूप का उपयोग करने की आवश्यकता होगी।
डेविड बेरी

@ डेविडबियर मुझे इस सिंगलटन क्लास के अंदर एक फ़ंक्शन को कैसे कॉल करना चाहिए? मुझे myClass.saredInstance की पहली कॉल पर एक फ़ंक्शन की आवश्यकता है।
अमीट धस

163

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

class Singleton  {
   static let sharedInstance = Singleton()
}

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

अपडेट : यह अब आधिकारिक डॉक्स में वर्णित एकलताओं को परिभाषित करने का आधिकारिक तरीका है !

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

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

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

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

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

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

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


2
कोई भी केवल इस उत्तर को पढ़ रहा है: टोकन को स्थिर बनाने के लिए याद रखें, अन्यथा व्यवहार अपरिभाषित है। संपूर्ण कोड के लिए डेविड का संपादित प्रश्न देखें।
nschum

@nschum अन्यथा, व्यवहार अपरिभाषित नहीं है, यह सिर्फ एक अच्छी तरह से परिभाषित तरीके से टूट गया है: ब्लॉक हमेशा निष्पादित होगा।
माइकल

@ मिचेल: प्रलेखन बताता है कि यह अपरिभाषित है। वर्तमान व्यवहार इसलिए संयोग है।
nschum

1
यह एक अजीब बात है। यदि दस्तावेज़ीकरण इसे "अपरिभाषित" कहता है, तो इसका मतलब है कि जिसने भी कोड लिखा है वह जो भी करता है उससे कोई वादा नहीं करता है। यदि चर स्थिर है तो यह जानने के लिए कोड के साथ कुछ नहीं करना है। इसका मतलब सिर्फ इतना है कि वर्तमान (या स्पष्ट) व्यवहार पर भरोसा नहीं किया जा सकता है।
nschum

6
आप के private init() {}आरंभिक के रूप में जोड़ना चाह सकते हैं SingletonClass। बाहर से तात्कालिकता को रोकने के लिए।
रिण्टारो

46

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

class MySingleton {

    static let sharedMySingleton = MySingleton()

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

35

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

var tpScopeManagerSharedInstance = TPScopeManager()

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

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

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


3
क्यों एक "var" और बहुत कुछ "let"?
Stephan

1
हो सकता है कि कोई जाने दे, मैंने केवल एक संस्करण के साथ इसका परीक्षण किया।
क्रिश गेल्सी

मुझे यह उत्तर पसंद है, हालांकि मुझे इंटरफ़ेस बिल्डर से इस (सिंगलटन) तक पहुंचने की आवश्यकता है। किसी भी विचार पर मैं इस tpScopeManagerSadedInstance को IB से कैसे प्राप्त कर सकता हूं। साभार ।-
लुइस

यह एक सिंगलटन होने का मेरा पसंदीदा तरीका है। इसमें सभी सामान्य विशेषताएं हैं (थ्रेड-सेफ्टी और आलसी इंस्टेंटेशन) और यह एक बहुत ही हल्के सिंटैक्स का समर्थन करता है: TPScopeManager.sharedInstance.doIt()हर समय लिखने की आवश्यकता नहीं है , बस अपनी कक्षा का नाम रखें TPScopeManagerClass, कक्षा के बगल में यह घोषणा है public let TPScopeManager = TPScopeManagerClass(), और बस लिखने का उपयोग करते समय TPScopeManager.doIt()। बहुत साफ!
एलेक्स

अतिरिक्त आवृत्तियों के निर्माण को रोकने के लिए यहां कुछ भी नहीं है TPScopeManager, और इसलिए यह परिभाषा से एक सिंगलटन नहीं है
कालेब

28

स्विफ्ट सिंगलेटों को कोको के ढांचे में वर्ग कार्यों, जैसे NSFileManager.defaultManager(), के रूप में उजागर किया जाता है NSNotificationCenter.defaultCenter()। तो यह वर्ग व्यवहार के रूप में इस व्यवहार को दर्पण करने के लिए और अधिक समझ में आता है, बल्कि कुछ अन्य समाधानों के रूप में एक वर्ग चर के बजाय। उदाहरण के लिए:

class MyClass {

    private static let _sharedInstance = MyClass()

    class func sharedInstance() -> MyClass {
        return _sharedInstance
    }
}

के माध्यम से सिंगलटन प्राप्त करें MyClass.sharedInstance()


1
LearnCocos2D :) की टिप्पणी के लिए upvoted शैली के लिए भी।
x4h1d

2
वैश्विक चर को कक्षा के अंदर स्थैतिक के माध्यम से एक वर्ग चर में बदलना चाहिए।
मलहल

2
@ जब किसी वैरिएबल को निजी के रूप में चिह्नित किया जाता है, लेकिन किसी वर्ग के बाहर, यह वैश्विक नहीं है - लेकिन केवल उस फ़ाइल में स्कोप किया जाता है, जो क्लास के अंदर एक स्टैटिक बहुत समान रूप से काम करेगा, लेकिन मैंने स्टेटिक का उपयोग करने के लिए उत्तर अपडेट कर दिया है। जैसा कि आपने सुझाव दिया है, क्योंकि यह बेहतर है कि यदि आप फ़ाइल के भीतर कई कक्षाओं का उपयोग करते हैं तो यह कक्षा में परिवर्तनशील है।
रयान

1
"स्विफ्ट सिंगलेट्स कोको फ्रेमवर्क में क्लास फ़ंक्शंस के रूप में उजागर होते हैं" ... स्विफ्ट 3 में नहीं। वे अब आमतौर पर staticगुण हैं।
रोब

17

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

class Singleton {
    static let sharedInstance = Singleton()
}

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

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

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


आप स्थैतिक लेट इंस्टेंस को शून्य पर कैसे सेट कर सकते हैं?
gpichler

1
@ user1463853 - आप नहीं कर सकते, और आम तौर पर नहीं करना चाहिए।
रोब

16

स्विफ्ट 4+

protocol Singleton: class {
    static var sharedInstance: Self { get }
}

final class Kraken: Singleton {
    static let sharedInstance = Kraken()
    private init() {}
}

2
यह अंतिम वर्ग की जरूरत है, क्या आप अधिक अंतर की व्याख्या कर सकते हैं, coz मैं संरचना के साथ सिंगलटन के अन्य समाधान के साथ मुद्दा है
राहील सादिक

क्या वह निजी ओवरराइड init () {}
NSRover

8

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

struct StaticRank {
    static let shared = RankMapping()
}

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

class var shared:RankMapping {
    return StaticRank.shared
}

मुझे पूरा यकीन है कि इस डिफ़ॉल्ट स्थैतिक वाक्यविन्यास का उपयोग करने से सभी कष्टप्रद कार्य होंगे।
Eonil

दुर्भाग्य से स्टैटिक्स केवल संरचनाओं के अंदर काम करते हैं, इसलिए यही पैटर्न है।
user2485100

मेरा इरादा यह था कि हमें dispatch_onceसामान का उपयोग नहीं करना है । मैं आपकी शैली पर दांव लगा रहा हूं। :)
Eonil

ना classके बराबर एक वर्ग घोषणा के भीतर staticएक struct घोषणा में?
रसेल बोरोगोव

@Sam हाँ यह है। फाइल और इनिशियलाइज़ेशन पर Apple ब्लॉग प्रविष्टि देखें जिससे यह स्पष्ट हो जाता है कि इस dispatch_onceक्षमता से ग्लोबल्स और स्टैम्पस के दोनों सदस्य और गणमान्य सदस्य लाभान्वित होते हैं ।
राब

5

संक्षेप में,

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

आप फाइल और इनिशियलाइज़ेशन पढ़ना चाह सकते हैं

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


4

यदि आप ऑब्जेक्टिव-सी में अपनी स्विफ्ट सिंगलटन क्लास का उपयोग करने की योजना बना रहे हैं, तो इस सेटअप में कंपाइलर उपयुक्त ऑब्जेक्टिव-सी-हेडर (ओं) को उत्पन्न करेगा:

class func sharedStore() -> ImageStore {
struct Static {
    static let instance : ImageStore = ImageStore()
    }
    return Static.instance
}

फिर ऑब्जेक्टिव-सी क्लास में आप अपने सिंगलटन को उस तरह से कॉल कर सकते हैं जैसा आपने प्री-स्विफ्ट दिनों में किया था:

[ImageStore sharedStore];

यह सिर्फ मेरा सरल कार्यान्वयन है।


यह वास्तव में अन्य उदाहरणों की तुलना में अधिक संक्षिप्त और सही है क्योंकि इसे उसी तरह लागू किया जाता है जैसे कि अन्य स्विफ्ट सिंगललेट्स हैं। अर्थात्: वर्ग कार्यों के रूप में की तरह है NSFileManager.defaultManager(), लेकिन अभी भी स्विफ्ट की आलसी धागा सुरक्षित स्थिर सदस्य तंत्र का उपयोग करता है।
लेस्ली गॉडविन

कोको आम तौर पर इन स्थैतिक गुणों के रूप में लागू होता है, आजकल वर्ग कार्यों के रूप में नहीं।
रोब

मुझे पता है कि, मेरी टिप्पणी 2 साल से अधिक पुरानी है। उल्लेख करने के लिए धन्यवाद।
माइकल

4

पहला उपाय

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()        
}

4
final class MySingleton {
     private init() {}
     static let shared = MySingleton()
}

फिर बुलाओ;

let shared = MySingleton.shared

खैर केवल अंकन नहीं के लिए किया जाता initके रूप में private, लेकिन यह भी करने के लिए sharedMyModelके रूप में final! भविष्य के पाठकों के लिए, स्विफ्ट 3 में, हम sharedMyModelबस नाम बदलने के लिए इच्छुक हो सकते हैं shared
रॉब

यह एकमात्र सही उत्तर है, सिवाय इसके कि अधिरचना और सुपर.इन करने के लिए कॉल गलत है और संकलन भी नहीं होगा।
माइकल मॉरिस

4

उपयोग:

class UtilSingleton: NSObject {

    var iVal: Int = 0

    class var shareInstance: UtilSingleton {
        get {
            struct Static {
                static var instance: UtilSingleton? = nil
                static var token: dispatch_once_t = 0
            }
            dispatch_once(&Static.token, {
                Static.instance = UtilSingleton()
            })
            return Static.instance!
        }
    }
}

कैसे इस्तेमाल करे:

UtilSingleton.shareInstance.iVal++
println("singleton new iVal = \(UtilSingleton.shareInstance.iVal)")

यह ठीक उसी तरह का है जैसे मैं वर्तमान उत्तर के रास्ते पर गया था। चूँकि ग्लोबल वैरिएबल को आलसी और थ्रेड-सेफ दोनों तरह से इनिशियलाइज़ किया जाता है, अतिरिक्त जटिलता का कोई कारण नहीं है।
डेविड बेरी

@ वैश्विक वैरिएबल नहीं होने के अलावा अन्य। :)
hpique

@hpique नहीं, मेरे पहले के प्रयासों की तरह। संपादन इतिहास को देखें।
डेविड बेरी

4

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

class Shared: NSObject {

    static let sharedInstance = Shared()

    private override init() { }
}

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


क्यों एक NSObjectउपवर्ग? इसके अलावा, यह मूल रूप से stackoverflow.com/a/28436202/1187415 के समान प्रतीत होता है ।
मार्टिन आर।

3

Apple डॉक्स (स्विफ्ट 3.0.1) से,

आप केवल एक स्थिर प्रकार की संपत्ति का उपयोग कर सकते हैं, जिसे केवल एक बार एकाधिक थ्रेड्स में एक्सेस किए जाने पर, केवल एक बार ही लाज़िली प्रारंभ करने की गारंटी दी जाती है:

class Singleton {
    static let sharedInstance = Singleton()
}

यदि आपको प्रारंभ से परे अतिरिक्त सेटअप करने की आवश्यकता है, तो आप वैश्विक स्थिरांक को बंद करने के आह्वान का परिणाम बता सकते हैं:

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

3

मैं आपको सुझाव दूंगा enum, जैसा कि आप जावा, जैसे में उपयोग करेंगे

enum SharedTPScopeManager: TPScopeManager {
    case Singleton
}

IMO, यह सिंगलटन को लागू करने का एकमात्र सही स्विफ्ट तरीका है। अन्य उत्तर ObjC / C / C ++ तरीका है
ब्रायन चेन

क्या आप इस उत्तर पर विस्तार से बता सकते हैं? यह मेरे लिए स्पष्ट नहीं है, जहां सिंगलटन इस स्निपेट से तुरंत जुड़ा हुआ है
केनी विंकर

@KennyWinker मेरे पास Apple डेवलपर लॉगिन नहीं है, इसलिए कोई भी स्विफ्ट नहीं है और इसलिए जब जवाब होता है तो मैं इसका जवाब नहीं दे सकता। जावा में, यह पहले उपयोग पर है। शायद आप इसे इनिशियलाइज़ेशन पर प्रिंट के साथ आज़मा सकते हैं और देख सकते हैं कि प्रिंट लॉन्च के बाद होता है या एक्सेस के बाद। यह इस बात पर निर्भर करेगा कि कंपाइलर द्वारा एनम कैसे लागू किया जाता है।
हावर्ड लोवेट

@KennyWinkler: Apple ने स्पष्ट किया है कि यह कैसे काम करता है, डेवलपर देखें ।apple.com/swift/blog/?id=7 । इसमें वे कहते हैं कि "एक वैश्विक के लिए इनिशियलाइज़र को पहली बार चलाएं जो कि संदर्भित है, जावा के समान" और विशेष रूप से। वे यह भी कहते हैं कि जिन आवरणों के नीचे वे "प्रेषण_का उपयोग कर रहे हैं, यह सुनिश्चित करने के लिए कि आरंभिक परमाणु है"। इसलिए एनम लगभग निश्चित रूप से जाने का तरीका है जब तक कि आपके पास करने के लिए कुछ फैंसी init नहीं है, तो एक निजी स्थिर समाधान है।
हॉवर्ड लोवेट

2

केवल संदर्भ के लिए, यहां जैक वू / hpique के नेस्टेड स्ट्रक्चर कार्यान्वयन का एक उदाहरण सिंग्लटन कार्यान्वयन है। कार्यान्वयन यह भी दिखाता है कि संग्रह कैसे काम कर सकता है, साथ ही साथ कुछ कार्य भी कर सकते हैं। मुझे इसका उदाहरण पूरा नहीं मिला, इसलिए उम्मीद है कि इससे किसी को मदद मिलेगी!

import Foundation

class ItemStore: NSObject {

    class var sharedStore : ItemStore {
        struct Singleton {
            // lazily initiated, thread-safe from "let"
            static let instance = ItemStore()
        }
        return Singleton.instance
    }

    var _privateItems = Item[]()
    // The allItems property can't be changed by other objects
    var allItems: Item[] {
        return _privateItems
    }

    init() {
        super.init()
        let path = itemArchivePath
        // Returns "nil" if there is no file at the path
        let unarchivedItems : AnyObject! = NSKeyedUnarchiver.unarchiveObjectWithFile(path)

        // If there were archived items saved, set _privateItems for the shared store equal to that
        if unarchivedItems {
            _privateItems = unarchivedItems as Array<Item>
        } 

        delayOnMainQueueFor(numberOfSeconds: 0.1, action: {
            assert(self === ItemStore.sharedStore, "Only one instance of ItemStore allowed!")
        })
    }

    func createItem() -> Item {
        let item = Item.randomItem()
        _privateItems.append(item)
        return item
    }

    func removeItem(item: Item) {
        for (index, element) in enumerate(_privateItems) {
            if element === item {
                _privateItems.removeAtIndex(index)
                // Delete an items image from the image store when the item is 
                // getting deleted
                ImageStore.sharedStore.deleteImageForKey(item.itemKey)
            }
        }
    }

    func moveItemAtIndex(fromIndex: Int, toIndex: Int) {
        _privateItems.moveObjectAtIndex(fromIndex, toIndex: toIndex)
    }

    var itemArchivePath: String {
        // Create a filepath for archiving
        let documentDirectories = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
        // Get the one document directory from that list
        let documentDirectory = documentDirectories[0] as String
        // append with the items.archive file name, then return
        return documentDirectory.stringByAppendingPathComponent("items.archive")
    }

    func saveChanges() -> Bool {
        let path = itemArchivePath
        // Return "true" on success
        return NSKeyedArchiver.archiveRootObject(_privateItems, toFile: path)
    }
}

और यदि आप उन कार्यों में से कुछ को पहचान नहीं पाए हैं, तो यहां एक छोटी सी जीवित स्विफ्ट उपयोगिता फ़ाइल है जिसका मैं उपयोग कर रहा हूं:

import Foundation
import UIKit

typealias completionBlock = () -> ()

extension Array {
    func contains(#object:AnyObject) -> Bool {
        return self.bridgeToObjectiveC().containsObject(object)
    }

    func indexOf(#object:AnyObject) -> Int {
        return self.bridgeToObjectiveC().indexOfObject(object)
    }

    mutating func moveObjectAtIndex(fromIndex: Int, toIndex: Int) {
        if ((fromIndex == toIndex) || (fromIndex > self.count) ||
            (toIndex > self.count)) {
                return
        }
        // Get object being moved so it can be re-inserted
        let object = self[fromIndex]

        // Remove object from array
        self.removeAtIndex(fromIndex)

        // Insert object in array at new location
        self.insert(object, atIndex: toIndex)
    }
}

func delayOnMainQueueFor(numberOfSeconds delay:Double, action closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue()) {
            closure()
    }
}

2

तेजी से, आप निम्न तरीके से एक एकल वर्ग बना सकते हैं:

class AppSingleton: NSObject {

    //Shared instance of class
    static let sharedInstance = AppSingleton()

    override init() {
        super.init()
    }
}

1

मैं इस कार्यान्वयन को प्राथमिकता देता हूं:

class APIClient {

}

var sharedAPIClient: APIClient = {
    return APIClient()
}()

extension APIClient {
    class func sharedClient() -> APIClient {
        return sharedAPIClient
    }
}

1

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

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

1

केवल सही दृष्टिकोण नीचे है।

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

    private init() {}
}

उपयोग करने के लिए

let signleton = Singleton.sharedInstance

कारण:

  • static टाइप प्रॉपर्टी की गारंटी दी जाती है कि इसे एक ही बार में एक साथ शुरू किया जाए, तब भी जब इसे एक साथ कई थ्रेड्स पर एक्सेस किया जाता है, तो उपयोग करने की कोई आवश्यकता नहीं है dispatch_once
  • initविधि को निजीकृत करना इसलिए अन्य वर्गों द्वारा उदाहरण नहीं बनाया जा सकता है।
  • final वर्ग के रूप में आप चाहते हैं कि अन्य वर्ग सिंगलटन वर्ग को विरासत में न लें।

आपने क्लोज़र इनिशियलाइज़ेशन का उपयोग क्यों किया, जबकि आप सीधे उपयोग कर सकते हैंstatic let sharedInstance = Singleton()
abhimuralidharan

1
यदि आप कोई अतिरिक्त सेटअप नहीं करना चाहते हैं तो आप जो कह रहे हैं वह सही है।
सेबफ्रीक

1

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

let gScopeManagerSharedInstance = ScopeManager()

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

2
जैसा कि मैं अपनी टिप्पणियों में कहता हूं, ऐसा करने का एकमात्र कारण यह है कि भविष्य में किसी बिंदु पर आप वैश्विक चर को स्थानांतरित / छिपा सकते हैं और अधिक सिंगलटन जैसे व्यवहार प्राप्त कर सकते हैं। उस बिंदु पर, यदि सब कुछ एक सुसंगत पैटर्न का उपयोग कर रहा है, तो आप उपयोग को बदलने के बिना केवल सिंगलटन क्लासेस को स्वयं बदल सकते हैं।
डेविड बेरी

0
   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!
}

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

0

अतीत में सिंगलटन को महसूस करने के लिए स्विफ्ट, तीन तरीकों से ज्यादा कुछ नहीं है: वैश्विक चर, आंतरिक चर और प्रेषण_नहीं तरीके।

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

विधि 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

-1

यह थ्रेड सुरक्षित क्षमताओं के साथ सबसे सरल है। कोई अन्य धागा एक ही सिंगलटन ऑब्जेक्ट तक नहीं पहुंच सकता है, भले ही वे चाहें। स्विफ्ट 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!
        }
    }
}

2
स्टैटिक टाइप प्रॉपर्टी पर क्या फायदा है (जो कि एक ही बार में एक साथ कई थ्रेड्स में एक्सेस किए जाने पर, लाज़िली इनिशियलाइज़ होने की गारंटी है)?
मार्टिन आर

-1

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

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
    }
}
  • इस तरह से जब Singleton.sharedInstance()यह पहली बार कर रहा है तो इसका उदाहरण वापस आ जाएगाSingleton
  • जब कर SubSingleton.sharedInstance()पहले इसके बारे में उदाहरण के वापस आ जाएगी SubSingletonबनाया।
  • यदि उपरोक्त किया जाता है, तो SubSingleton.sharedInstance()है Singletonहै सच और एक ही उदाहरण प्रयोग किया जाता है।

इस पहले गंदे दृष्टिकोण के साथ मुद्दा यह है कि मैं इस बात की गारंटी नहीं दे सकता कि उपवर्ग लागू करेंगे dispatch_once_tऔर सुनिश्चित करेंगे कि sharedInstanceVarकेवल कक्षा में एक बार संशोधित किया जाए।

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


-2

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

let TEST = Test()

class Test {

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

private initपहले से ही यहाँ सुझाव दिया गया था: stackoverflow.com/a/28436202/1187415
मार्टिन आर

-2

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

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. उपयोगकर्ता को उप-क्रियान्वयन नहीं करने की याद दिलाता है
  2. अतिरिक्त उदाहरणों के निर्माण को रोकता है
  3. आलसी निर्माण और अद्वितीय तात्कालिकता सुनिश्चित करता है
  4. शॉर्टेंस सिंटैक्स (अवॉइड्स) (जैसे) एक्सेस एक्सेस की अनुमति देकर Singleton.instance
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.