Как инициализировать переменную, но после ее завершения ее значение является окончательным
У меня есть объектная переменная модели в 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") }
}
}