swift - সুইফ্টে একটি dispatch_once সিঙ্গলটন মডেল ব্যবহার করে




singleton (20)

আমি সুইফ্ট ব্যবহারের জন্য একটি উপযুক্ত এককোন মডেল কাজ করার চেষ্টা করছি। এ পর্যন্ত, আমি একটি অ-থ্রেড নিরাপদ মডেল হিসাবে কাজ করতে সক্ষম হয়েছে:

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 সঠিকভাবে সংজ্ঞায়িত করার ব্যাপার হতে পারে।


1.2 এর উপরে সুইফ্টের সর্বোত্তম পদ্ধতিটি এক-লাইন সিঙ্গল্টন হিসাবে -

class Shared: NSObject {

    static let sharedInstance = Shared()

    private override init() { }
}

এই পদ্ধতি সম্পর্কে আরও বিস্তারিত জানতে আপনি এই link দেখতে পারেন।


অতীতে একক্টন বুঝতে স্নিফ্ট, তিনটি উপায়ে আর কিছুই নয়: গ্লোবাল ভেরিয়েবল, অভ্যন্তরীণ ভেরিয়েবল এবং dispatch_once উপায়ে।

এখানে দুইটি ভাল সিঙ্গলটন রয়েছে। (নোট: কোনও ধরনের লেখা ব্যক্তিগতকরণের 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

আপনি যদি উদ্দেশ্য-সি-তে আপনার সুইফ্ট সিঙ্গল্টন ক্লাস ব্যবহার করার পরিকল্পনা করছেন, তবে এই সেটআপটিতে উপযুক্ত উদ্দেশ্য-সি-মত হেডার (গুলি) তৈরি করবে:

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

তারপর Objective-C ক্লাসে আপনি আপনার সিঙ্গল্টনকে প্রাক-সুইফ্ট দিনগুলিতে কীভাবে এটি করেছেন তা বলতে পারেন:

[ImageStore sharedStore];

এটি শুধু আমার সহজ বাস্তবায়ন।


আমি এই বাস্তবায়ন পছন্দ করি:

class APIClient {

}

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

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

আমি শুধু এই সাথে এসেছি, কিন্তু আমার একক্টনের প্রয়োজন ছিল উত্তরাধিকার অনুমতি, এবং এই সমাধানগুলির মধ্যে কোনটি আসলেই এটির অনুমতি দেয় নি।

তাই আমি এই সঙ্গে এসেছিলেন:

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 () হল সিঙ্গলটন সত্য এবং একই উদাহরণ ব্যবহার করা হয়।

এই প্রথম নোংরা পদ্ধতির সাথে সমস্যাটি হল যে আমি সাব্লকেসগুলি dispatch_once_t প্রয়োগ করতে পারব এবং নিশ্চিত করতে পারব যে ভাগ করা ইনস্ট্যান্সভার কেবল প্রতি ক্লাসে একবার সংশোধন করা হয় ...

আমি এটিকে আরও পরিমার্জন করার চেষ্টা করব, কিন্তু এটি দেখতে আকর্ষণীয় হবে যে এর বিরুদ্ধে কারো দৃঢ় অনুভূতি আছে কিনা (তার সাথে এটি ক্রিয়াপদ এবং এটি ম্যানুয়ালি আপডেট করতে হবে)।


একমাত্র সঠিক পদ্ধতি নিচে

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

    private init() {}
}

অ্যাক্সেস করতে

let signleton = Singleton.sharedInstance

কারণ:

  • স্ট্যাটিক টাইপ সম্পত্তিটি শুধুমাত্র একবার একবার শুরু হওয়া নিশ্চিত, এমনকি একাধিক থ্রেডগুলিতে একযোগে অ্যাক্সেস করার পরেই, তাই dispatch_once ব্যবহার করার প্রয়োজন নেই
  • Init পদ্ধতি privatizing তাই উদাহরণ অন্যান্য ক্লাস দ্বারা তৈরি করা যাবে না।
  • চূড়ান্ত বর্গ হিসাবে আপনি অন্যান্য ক্লাস একক্টন ক্লাস উত্তরাধিকারী চাই না

ডেভিডের বাস্তবায়ন দেখে, মনে হচ্ছে যে একটি সিলেন্টন ক্লাস ফাংশন ইনস্ট্যান্সের দরকার নেই, পদ্ধতিটি যেহেতু ভাগ করা ইনস্ট্যান্স ক্লাস পদ্ধতির মতোই একই জিনিস করছে। আপনাকে যা করতে হবে তা বিশ্বব্যাপী ধ্রুবক হিসাবে ঘোষণা করে এবং এটি হবে।

let gScopeManagerSharedInstance = ScopeManager()

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

ব্যবহার করুন:

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)")

শুধু রেফারেন্সের জন্য, এখানে জ্যাক উ / হ্পিকের নেস্টেড স্ট্রাক্ট বাস্তবায়নের সিঙ্গলটন বাস্তবায়ন উদাহরণ। বাস্তবায়ন কিভাবে সংরক্ষণাগার কাজ করতে পারে, পাশাপাশি কিছু সহকর্মী ফাংশন দেখায়। আমি এই উদাহরণটি সম্পূর্ণরূপে খুঁজে পাইনি, তাই আশা করি এটি কারো সাহায্য করবে!

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

সংক্ষেপে,

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

আপনি here পড়া করতে পারেন

গ্লোবাল ভেরিয়েবলের জন্য অলস সূচনাকারী (structs এবং enums এর স্ট্যাটিক সদস্যদের জন্যও) বিশ্বব্যাপী অ্যাক্সেস করা প্রথমবার চালানো হয় এবং প্রাথমিকভাবে এটি পারমাণবিক হয় তা নিশ্চিত করতে dispatch_once হিসাবে চালু করা হয়।


সুইফ্ট NSFileManager.defaultManager() কোকো ফ্রেমওয়ার্কগুলিতে ক্লাস ফাংশন হিসাবে উন্মুক্ত করা হয়, যেমন NSFileManager.defaultManager() , NSNotificationCenter.defaultCenter() , তাই আমি মনে করি এটি ক্লাসের ফাংশন হিসাবে আরও কিছু ইন্দ্রিয় তোলে যা এই আচরণকে মিরর করে NSNotificationCenter.defaultCenter() , অন্য কিছু সমাধান হিসাবে NSNotificationCenter.defaultCenter() পরিবর্তে ব্যবহার, যেমন

class MyClass {

    private static let _sharedInstance = MyClass()

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

MyClass.sharedInstance() মাধ্যমে MyClass.sharedInstance() পুনরুদ্ধার করুন।


সুইফ্টের বাস্তবায়ন আমার উপায় ...

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

tl; dr: যদি আপনি পূর্বের সংস্করণগুলি সমর্থন করতে চান তবে সুইফ্ট 1.2 বা তার উপরে এবং নেস্টেড স্ট্রাক পদ্ধতি ব্যবহার করে ক্লাস ধ্রুবক পদ্ধতিটি ব্যবহার করুন।

সুইফ্টের সাথে আমার অভিজ্ঞতা থেকে অলসন প্যাটার্ন বাস্তবায়নের জন্য তিনটি পদ্ধতি রয়েছে যা অলস সূচনা এবং থ্রেড নিরাপত্তা সমর্থন করে।

ক্লাস ধ্রুবক

class Singleton  {
   static let sharedInstance = Singleton()
}

এই পদ্ধতিটি অলস সূচনাকে সমর্থন করে কারণ সুইফ্ট অলসভাবে ধীরে ধীরে ক্লাস স্টোনেন্টগুলিকে (এবং ভেরিয়েবল) সূচনা করে এবং এর সংজ্ঞা দ্বারা সুরক্ষিত থ্রেড। এটি এখন একটি সিঙ্গলটন তাত্ক্ষণিকভাবে আনুষ্ঠানিকভাবে প্রস্তাবিত উপায়

সুইফ্ট 1.2 এ ক্লাস স্টেশন চালু করা হয়। যদি আপনি সুইফ্টের পূর্বের সংস্করণটিকে সমর্থন করতে চান, নীচের নেস্টেড struct পদ্ধতিটি ব্যবহার করুন অথবা বিশ্বব্যাপী ধ্রুবকটি ব্যবহার করুন।

নেস্টেড গঠন

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

এখানে আমরা একটি ক্লাস ধ্রুবক হিসাবে একটি নেস্টেড গঠন স্ট্যাটিক ধ্রুবক ব্যবহার করা হয়। সুইফ্ট 1.1 এবং তার আগে স্ট্যাটিক ক্লাস স্টোনগুলির অভাবের জন্য এটি একটি কার্যকারিতা, এবং এখনও স্ট্যাটিক স্টোনেন্ট এবং ফাংশনে ভেরিয়েবলের অভাবের জন্য কার্যকারিতা হিসাবে কাজ করে।

dispatch_once

ঐতিহ্যগত উদ্দেশ্য-সি পদ্ধতির সুইফ্ট পোর্ট করা। আমি মোটামুটি নিশ্চিত যে নেস্টেড struct পদ্ধতির উপর কোনও সুবিধা নেই তবে আমি এটিকে এখানে রেখে দিচ্ছি যেহেতু আমি সিনট্যাক্সে আকর্ষণীয় পার্থক্য খুঁজে পাচ্ছি।

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 প্রকল্প দেখুন।


অ্যাপল Docs থেকে (সুইফ্ট 3.0.1),

আপনি সহজেই স্ট্যাটিক টাইপ সম্পত্তির ব্যবহার করতে পারেন, যা শুধুমাত্র একবার একবার এলিজাবেড হওয়া নিশ্চিত, এমনকি একাধিক থ্রেডগুলি একযোগে অ্যাক্সেস করার পরেও নিশ্চিত করা হয়:

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

সঠিকতা প্রমাণের সাথে (সমস্ত ক্রেডিট here যায়), এখন singletons এর জন্য আগের কোনও পদ্ধতি ব্যবহার করার কোনো কারণ নেই।

আপডেট : অফিসিয়াল ডক্সে বর্ণিত হিসাবে এটি এখন একালেট সংজ্ঞায়িত করার সরকারী উপায়!

static বনাম class ব্যবহার করে উদ্বেগ হিসাবে। static class ভেরিয়েবলগুলি উপলব্ধ হওয়ার পরেও ব্যবহার করতে হবে। সিঙ্গলনগুলি বন্টন করা হয় না কারণ এটি বেস সিঙ্গলটের একাধিক দৃষ্টান্তের ফলস্বরূপ। static ব্যবহার করে এটি একটি সুন্দর, স্বতঃস্ফূর্ত ভাবে প্রয়োগ করে।

সুইফ্ট 1.0 এবং 1.1 এর জন্য:

সুইফ্টে সাম্প্রতিক পরিবর্তনগুলি, বেশিরভাগ নতুন অ্যাক্সেস কন্ট্রোল পদ্ধতি, আমি এখন singletons এর জন্য একটি বিশ্বব্যাপী পরিবর্তনশীল ব্যবহার করার ক্লিনার উপায়ের দিকে ঝুঁকে পড়েছি।

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

here সুইফ্ট ব্লগ নিবন্ধে উল্লেখ করা here :

গ্লোবাল ভেরিয়েবলের জন্য অলস সূচনাকারী (structs এবং enums এর স্ট্যাটিক সদস্যদের জন্যও) বিশ্বব্যাপী অ্যাক্সেস করা প্রথমবার চালানো হয় এবং প্রাথমিকভাবে এটি পারমাণবিক হয় তা নিশ্চিত করতে dispatch_once হিসাবে চালু করা হয়। এটি আপনার কোডে dispatch_once ব্যবহার করার জন্য একটি দুর্দান্ত উপায় সক্ষম করে: কেবল একটি প্রাইভেটাইজারের সাথে একটি বিশ্বব্যাপী পরিবর্তনশীল ঘোষণা করুন এবং এটি ব্যক্তিগতকে চিহ্নিত করুন।

একটি সিঙ্গলটন তৈরির এই পদ্ধতিটি থ্রেড নিরাপদ, দ্রুত, অলস, এবং বিনামূল্যেও ওজিজসি-তে বদ্ধ।


সুইফ্ট 4+

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

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

একটি সিলেটে ক্লাস তৈরি করতে স্ট্যাটিক পরিবর্তনশীল এবং প্রাইভেট ইনিশিয়েটিজার ব্যবহার করুন।

class MySingletonClass {

    static let sharedSingleton = MySingletonClass()

    private init() {}
}

এই আমার বাস্তবায়ন। এটি প্রোগ্রামারকে একটি নতুন উদাহরণ তৈরি করতে বাধা দেয়:

let TEST = Test()

class Test {

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

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

তারপর এটা কল করুন;

let shared = MySingleton.shared

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