Как инициализировать переменную, но после ее завершения ее значение является окончательным

У меня есть объектная переменная модели в Swift View Controller. То, что я хотел бы сделать, это то, что при инициализации VC у меня нет для этого значения. Но после асинхронного сетевого вызова у меня есть объект синтаксического анализа, который должен выполнять эта переменная, но с этого момента я не хочу ничего менять значение переменной модели.

Можно ли это сделать в Swift? если да, то как?

Ответ 1

На основании ответа Бабула Прабхакара, но немного более чистого.

Подход 1:

var test: String? { didSet { test = oldValue ?? test } }

test = "Initial string"
test = "Some other string"
test = "Lets try one last time"

print(test) // "Initial string"

Изменить: уменьшилось

Подход 2:

let value: String
value = "Initial string"

Я предполагаю, что второй подход - это "встроенная" опция Swift для объявления переменной один раз. Это возможно только тогда, когда переменная назначается сразу после объявления.

Ответ 2

Что вы можете сделать, это

private var myPrivateVar:String?;

var publicGetter:String {
    set {
        if myPrivateVar == nil {
            myPrivateVar = newValue;

        }

    }
    get {
        return myPrivateVar!;
    }
}

Ответ 3

Лично я бы пошел с подходом @Eendje или @Babul Prabhakar, если бы myPrivateVar был так или иначе установлен myPrivateVar nil установщик все еще мог писать дважды. Я хотел поделиться другим параметром, который guaranteed никогда не будет установлен дважды (если токен никогда не записывается!):

    private var token: dispatch_once_t = 0

    private var setOnce : String?

    var publicGetter: String {

        set (newValue) {
            dispatch_once(&token) {
                self.setOnce = newValue
            }
        }

        get {
            guard let setOnce = setOnce else {
                return ""
            }
            return setOnce
        }
    }

Функция dispatch_once() предоставляет простой и эффективный механизм для запуска инициализатора ровно один раз, аналогично pthread_once (3). Хорошо разработанный код скрывает использование отложенной инициализации. Например: пример:

источник

Ответ 4

Быстрая поддержка ленивых переменных. Например, следующая переменная будет установлена ​​на значение "Привет!". только при доступе.

// variable declaration, not yet initialized
lazy var myString = "Hi There!"


// myString gets initialized here since value is been accessed.
var someOtherVariable = myString

Ответ 5

Я боюсь, что в Swift нет традиционного способа, и на других языках тоже. (Традиционный способ означает, что вы используете ключевое слово поддерживаемого языка для своей цели). Вам трудно понять, что эта переменная была инициализирована до (без использования какой-либо переменной состояния для проверки).

Вы можете использовать этот шаблон дизайна: объявить все свойства как private (чтобы вы не могли устанавливать эти свойства где-то еще в вашем коде). И вы инициализируете все свойства в constructor. Таким образом, все свойства будут инициализированы только одним.

Objective-C и Swift 2 имеет модификатор доступа, такой как public protected private.

note: Swift 1 не имеет модификатора доступа.

Вот демонстрация в Swift 2:

class ViewModel {
    private var firstName : String;
    private var lastName : String;

    init (firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

Вот демонстрация в Objective-C:

@interface ViewModel : NSObject
    {
        @private
        NSString *firstName;   
        @private
        NSString *lastName;
    }      
    - (id)initWithFirstName:(NSString *)_firstName
                   lastName:(NSString *)_lastName       
    @end

    @implementation ViewModel     
    - (id)initWithFirstName:(NSString *)_firstName
                   lastName:(NSString *)_lastName
    {
        if( self = [super init] )
        {
            firstName = _firstName;
            lastName = _lastName;
        }       
        return self;
    }        
    @end

Надеюсь, что эта помощь:)

Ответ 6

Главный ответ с использованием didSet подвержен ошибкам - вызывающая сторона может попытаться установить переменную и не будет уведомлена о том, что новое значение игнорируется, что может привести к всевозможным трудным исправлениям ошибок в дальнейшем.

Предполагая, что вы хотите, чтобы значение было не ноль:

var test: String! {
    willSet(newTest) {
        guard test == nil, newTest != nil else { fatalError("value was already set") }
    }
}