programing

Swift에서 dispatch_once singleton 모델 사용

sourcejob 2023. 4. 19. 22:56
반응형

Swift에서 dispatch_once singleton 모델 사용

스위프트에 적합한 싱글톤 모델을 개발 중입니다.지금까지 스레드 이외의 세이프 모델을 입수할 수 있었습니다.

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

on on on on on on on on on on on on on on 에 컴파일러 오류가 요.dispatch_once 표시:

식의 형식 'Void'를 형식 '()'으로 변환할 수 없습니다.

여러 가지 다른 종류의 구문을 사용해 봤는데 모두 같은 결과가 나온 것 같습니다.

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

의의 what what what of of of of of of of of of of of of 의 적절한 용법은 입니까?dispatch_onceSwift ★★★★★★★★★★★★★★★★★★★★★★★★★?에 이 줄 요.() 메세지에 , 「이러다 「이러다」, 「이러다」, 「이러다」의 가 될 생각합니다.dispatch_once_t이치노

tl;dr: Swift 1.2 이상을 사용하는 경우 클래스 상수 접근 방식을 사용하고 이전 버전을 지원해야 하는 경우 중첩 구조 접근 방식을 사용합니다.

Swift에 대한 제 경험상, 느린 초기화 및 스레드 안전성을 지원하는 싱글톤 패턴을 구현하기 위한 세 가지입니다.

클래스 상수

class Singleton  {
   static let sharedInstance = Singleton()
}

은 Swift가 상수 변수)를 lazy하게 에 느린 하며, "Swift"의 .let이것은 싱글톤을 인스턴스화하기 위해 공식적으로 권장되는 방법입니다.

클래스 상수는 Swift 1.2에서 도입되었습니다.이전 버전의 Swift를 지원해야 하는 경우 아래의 중첩 구조 접근법 또는 전역 상수를 사용하십시오.

중첩 구조

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

여기서는 클래스 상수로 중첩 구조의 정적 상수를 사용합니다.이는 Swift 1.1 이전 버전에서 정적 클래스 상수가 없는 경우의 회피책이며 함수에 정적 상수 및 변수가 없는 경우의 회피책으로도 기능합니다.

디스패치_1회

기존의 Objective-C 접근 방식은 Swift에 이식되었습니다.중첩된 구조 접근법보다 장점이 없다는 것은 확실하지만 구문 차이가 흥미롭기 때문에 여기에 두겠습니다.

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 프로젝트를 참조하십시오.

둘 된다는 것을 .dispatch_once)

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

        return Singleton.instance
    }
}

이를 통해 정적 구조 요소의 느리고 스레드 세이프한 자동 초기화를 활용하여 실제 구현을 소비자로부터 안전하게 숨기고 모든 것을 읽기 쉽도록 컴팩트하게 구분하여 가시적인 글로벌 변수를 제거합니다.

애플은 느린 이니셜라이저가 스레드 세이프하다는 것을 명확히 했습니다.★★★★★★★★★★★★★★★★★★,dispatch_once symant (유사 보호)

글로벌 변수(구조체 및 enum의 스태틱멤버도 마찬가지)의 레이지 이니셜라이저는 글로벌에 처음 액세스 할 때 실행되며 초기화가 원자적인지 확인하기 위해 dispatch_1회 실행됩니다.이를 통해 코드 내에서 dispatch_one을 사용하는 쿨한 방법이 가능해집니다.이니셜라이저를 사용하여 글로벌 변수를 선언하고 프라이빗 마크를 붙이기만 하면 됩니다.

여기서부터

Swift 1.2 이상의 경우:

class Singleton  {
   static let sharedInstance = Singleton()
}

정확성 증명(모든 신용은 여기에 있음)을 통해 싱글톤에 대해 이전 방법을 사용할 이유가 거의 또는 전혀 없습니다.

업데이트: 이제 공식 문서에 설명된 대로 싱글톤을 정의하는 공식 방법이 되었습니다!

의 우려에 대해서static »classstatic해도 좋다class변수를 사용할 수 있게 됩니다.싱글톤은 서브클래스가 되지 않습니다.그것은 베이스 싱글톤의 여러 인스턴스가 발생하기 때문입니다.「」를 사용합니다.static멋지고 재빠른 방법으로 시행하고 있습니다.

Swift 1.0 및 1.1의 경우:

최근 Swift의 변화(대부분의 새로운 접근 제어 방식)에 따라 싱글톤에 대한 글로벌 변수를 보다 깔끔하게 사용하는 쪽으로 기울고 있습니다.

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

Swift 블로그 기사에서 언급한 바와 같이 다음과 같습니다.

글로벌 변수(구조체 및 enum의 스태틱멤버도 마찬가지)의 레이지 이니셜라이저는 글로벌에 처음 액세스 할 때 실행되며 초기화가 원자적인지 확인하기 위해 dispatch_1회 실행됩니다.이를 통해 코드 내에서 dispatch_one을 사용하는 쿨한 방법이 가능해집니다.이니셜라이저를 사용하여 글로벌 변수를 선언하고 프라이빗 마크를 붙이기만 하면 됩니다.

이 싱글톤 작성 방법은 스레드 세이프, 고속, 레이지이며 ObjC에도 무료로 브리지 됩니다.

이제 Swift 1.2 이후에서는 클래스의 정적 변수/정수를 지원합니다.따라서 정적 상수를 사용할 수 있습니다.

class MySingleton {

    static let sharedMySingleton = MySingleton()

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

그것을 하는 더 좋은 방법이 있다.클래스 선언 위에 있는 클래스의 글로벌 변수를 다음과 같이 선언할 수 있습니다.

var tpScopeManagerSharedInstance = TPScopeManager()

변수 중 가 "init"으로 호출됩니다.dispatch_once재빠르다레퍼런스를 취득하고 싶은 클래스에서, 다음의 조작을 실시합니다.

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

따라서 기본적으로 공유 인스턴스 코드 블록 전체를 제거할 수 있습니다.

스위프트 싱글톤은 코코아 프레임워크에서 클래스 함수로 노출된다.NSFileManager.defaultManager(),NSNotificationCenter.defaultCenter()g서클른른른른 。

class MyClass {

    private static let _sharedInstance = MyClass()

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

.MyClass.sharedInstance().

Apple의 설명서에 따르면 Swift에서 가장 쉬운 방법은 static type 속성을 사용하는 것이라고 여러 번번이 반복되고 있습니다.

class Singleton {
    static let sharedInstance = Singleton()
}

단, 단순한 컨스트럭터 호출을 넘어 추가 셋업을 수행하는 방법을 찾는 경우 즉시 호출된 닫힘을 사용하는 것이 중요합니다.

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

이것은 스레드 세이프가 보장되며 한 번만 느긋하게 초기화됩니다.

스위프트 4 이상

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

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

Apple의 샘플 코드를 보고 이 패턴을 발견했습니다.Swift가 통계학을 어떻게 다루는지 모르겠지만, C#에서는 이 방법이 안전할 것입니다.Objective-C interop의 속성과 방법을 모두 포함합니다.

struct StaticRank {
    static let shared = RankMapping()
}

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

class var shared:RankMapping {
    return StaticRank.shared
}

한마디로

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

파일과 초기화를 읽을 수 있습니다.

및 의 레이지 했을 때 되며, """ ("enum")"으로 됩니다.dispatch_once초기화가 원자성이라는 것을 확인합니다.

Objective-C에서 Swift singleton 클래스를 사용할 예정이라면 이 셋업에서는 컴파일러가 적절한 Objective-C 유사 헤더를 생성합니다.

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

그런 다음 Objective-C 클래스에서 스위프트 이전의 방식으로 싱글톤을 부를 수 있습니다.

[ImageStore sharedStore];

이것은 단지 나의 간단한 구현입니다.

첫 번째 해결책

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()        
}
final class MySingleton {
     private init() {}
     static let shared = MySingleton()
}

그럼 불러주세요.

let shared = MySingleton.shared

용도:

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

1.2 이상의 스위프트에서 가장 좋은 접근법은 한 줄짜리 싱글톤이다.

class Shared: NSObject {

    static let sharedInstance = Shared()

    private override init() { }
}

이 접근법에 대한 자세한 내용은 이 링크를 참조하십시오.

Apple Docs(Swift 3.0.1)에서

여러 스레드에 동시에 액세스해도 한 번만 느긋하게 초기화할 수 있는 static type 속성을 사용할 수 있습니다.

class Singleton {
    static let sharedInstance = Singleton()
}

초기화를 넘어 추가 설정을 수행해야 하는 경우 폐쇄 호출 결과를 글로벌 상수에 할당할 수 있습니다.

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

는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★를 추천합니다.enum(Java)와할 수 있습니다

enum SharedTPScopeManager: TPScopeManager {
    case Singleton
}

참고로 Jack Wu/hpique의 Nested Structure 구현의 Singleton 구현 예를 소개합니다.또, 어카이브(archive)가 어떻게 기능할 수 있는지를 실장하고 있습니다.저는 이 완전한 예를 찾을 수 없었습니다. 그래서 이것이 누군가에게 도움이 되기를 바랍니다!

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

이러한 기능 중 일부를 인식하지 못한 경우, 다음은 제가 사용하고 있는 Swift 유틸리티 파일입니다.

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 AppSingleton: NSObject {

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

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

저는 이 구현을 선호합니다.

class APIClient {

}

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

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

스위프트에서의 내 실장 방식은...

Configuration Manager.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

올바른 유일한 접근법은 다음과 같습니다.

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

    private init() {}
}

접속처

let signleton = Singleton.sharedInstance

이유:

  • static은 여러 에 동시에 에도 한 되므로 type을 사용할 .dispatch_once
  • init다른 클래스에서 인스턴스를 만들 수 없습니다.
  • final다른 클래스가 싱글톤 클래스를 상속하지 않도록 합니다.

함수 David는 것 .instanceMethodlet 같은 일을 하고 있다sharedInstance이 값을 글로벌 상수로 선언하기만 하면 됩니다.

let gScopeManagerSharedInstance = ScopeManager()

class ScopeManager {
   // No need for a class method to return the shared instance. Use the gScopeManagerSharedInstance directly. 
}
   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!
}

과거의 싱글톤을 실현하는 것은 글로벌 변수, 내부 변수, 디스패치 세 가지 방법에 지나지 않는다.

여기 좋은 싱글톤 두 개가 있다.(주: 어떤 종류의 글을 쓰든 민영화의 init() 방법에 유의해야 한다.Swift에서는 오브젝트의 컨스트럭터 디폴트가 모두 public이므로 init을 private로 변경할 수 있습니다.이 클래스의 다른 오브젝트는 디폴트 초기화 메서드로 오브젝트를 작성할 수 없습니다.)

방법 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

스위프트 5.2

하다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 이런 식으로 수 요.Self : .

static let shared = Self()

그리고 다음과 같은 유형 안에 있어야 합니다.

class SomeTypeWithASingletonInstance {
   static let shared = Self()
}

이것은 스레드 세이프 기능을 갖춘 가장 단순한 것입니다.다른 스레드는 원하는 경우에도 동일한 싱글톤 객체에 액세스할 수 없습니다.스위프트 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!
        }
    }
}

저는 제 독신에게 상속을 허락하라고 요구했지만, 실제로 허락한 해결책은 없었습니다.그래서 생각해낸 건

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, 「 」가 「 」를 확인해 주세요.sharedInstanceVar1번으로 하다.

좀 더 다듬어 보겠습니다만, 이것에 대해 강한 감정을 가지고 있는 사람이 있는지 어떤지(수동으로 갱신할 필요가 있는 것 이외에는) 확인해 보는 것도 재미있을 것 같습니다.

이것이 나의 실장입니다.또한 프로그래머가 새 인스턴스를 만드는 것도 방지합니다.

let TEST = Test()

class Test {

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

다음 구문을 사용합니다.

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

이는 Swift 1.2부터4까지 동작하며 다음과 같은 장점이 있습니다.

  1. 구현 서브클래스를 사용하지 않도록 사용자에게 경고합니다.
  2. 추가 인스턴스 생성 방지
  3. 느린 생성과 고유한 인스턴스화를 보장합니다.
  4. 을 허용하여 을합니다.Singleton.instance

언급URL : https://stackoverflow.com/questions/24024549/using-a-dispatch-once-singleton-model-in-swift

반응형