Синглтон со свойствами в Swift 3

88

В документе Apple « Использование Swift с Cocoa и Objective-C» (обновленном для Swift 3) они приводят следующий пример шаблона Singleton:

class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()

        // setup code

        return instance
    }()
}

Представим, что этот синглтон должен управлять переменным массивом строк. Как / где мне объявить это свойство и убедиться, что оно правильно инициализируется пустым [String]массивом?

Роберт Джозеф
источник

Ответы:

236

Для меня это лучший способ сделать init приватным. Синтаксис Swift 3 \ 4 \ 5

// MARK: - Singleton

final class Singleton {

    // Can't init is singleton
    private init() { }

    // MARK: Shared Instance

    static let shared = Singleton()

    // MARK: Local Variable

    var emptyStringArray = [String]()

}
ЯннСтеф
источник
4
Я поддержал этот ответ, но для соответствия синтаксису Swift 3 «sharedInstance» следует заменить на «shared».
B-Rad
1
Если не будет регресса от swift 2 к swift 3, то этого не
произойдет,
1
Тип после shared можно не указывать, верно? static let shared = Singleton()
Крисвиллоу
1
@YannickSteph, тебе не нужно писать, static let shared: Singleton = Singleton()ты можешь просто написатьstatic let shared = Singleton()
Крисвиллоу
3
@RomanN Нет, вы не можете переопределить init, потому что он не наследует класс. Если вы можете это сделать, на этом примере final class Singleton: NSObject { private override init() { } }
YannSteph
59

Вы можете инициализировать пустой массив следующим образом.

class Singleton {

    //MARK: Shared Instance

    static let sharedInstance : Singleton = {
        let instance = Singleton(array: [])
        return instance
    }()

    //MARK: Local Variable

    var emptyStringArray : [String]

    //MARK: Init

    init( array : [String]) {
        emptyStringArray = array
    }
}

Или, если вы предпочитаете другой подход, подойдет этот.

class Singleton {

    //MARK: Shared Instance

    static let sharedInstance : Singleton = {
        let instance = Singleton()
        return instance
    }()

    //MARK: Local Variable

    var emptyStringArray : [String]? = nil

    //MARK: Init

    convenience init() {
        self.init(array : [])
    }

    //MARK: Init Array

    init( array : [String]) {
        emptyStringArray = array
    }
}

источник
Этот метод не работает в расширении? extension Cache { static let sharedInstance: Cache = { let instance = Cache() return instance }() }
Эндрю
1
Интересно, что Apple использует class varв iOS 10 для синглтонов (например, UIApplication). Будет ли их реализация такой же?
jjatie
2
Я предпочитаю одноэлементные методы инициализации , как privateметоды не даже internal. Это не позволяет другим использовать инициализатор по умолчанию '()' для этого класса.
Kumar C
1
@KumarC Вы правы, разве это не решит проблему, если мы добавим privateв init.
@TikhonovAlexander Не могли бы вы принести дополнительную информацию?
Dominique Vial
30

Согласно документации Apple: в Swift вы можете просто использовать свойство статического типа, которое гарантированно будет лениво инициализировано только один раз, даже при одновременном доступе через несколько потоков .

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()
}

С методом инициализации:

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()

    // MARK: - Initializer

    private init() {
    }

}
Мехул Соджитра
источник
3
почему init () не закрытый?
XcodeNOOB
0

Любая инициализация будет выполняться в методе инициализации. Здесь нет разницы между синглтоном и не-синглом.

скряга729
источник
26
Дополнительный фрагмент кода, который напрямую отвечает на вопрос, сделает этот ответ более полезным.
Реда Лемеден,