Ложная загрузка свойств в быстрой
Я пытаюсь обернуть голову вокруг языка Swift. Общий шаблон при построении представлений в коде с Objective-C заключается в переопределении свойств пользовательского интерфейса и ленивой загрузке их так:
@property(nonatomic, strong) UILabel *myLabel;
- (UILabel *)myLabel
{
if (!_myLabel) {
_myLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 75.0f, 320.0f, 20.0f)];
[_myLabel setFont:[UIFont subHeadlineFont]];
[_myLabel setTextColor:[UIColor subHeadlineColor]];
[_myLabel setText:@"Hello World"];
}
return _myLabel;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.myLabel];
}
Это позволяет настраивать UIElements в автономном режиме в пределах их установки, но не приводит к их переконфигурированию каждый раз.
Кажется, у нас нет доступа к хранилищу в Swift, а ключевое слово @lazy
не имеет одинаковой семантики.
Мне любопытно, если кто-то идентифицировал подобный шаблон в Swift, который позволяет сохранить конфигурацию переменных и констант вместе с их объявлением аккуратным синтаксическим способом, который не приводит к реконфигурации каждый раз?
Ответы
Ответ 1
Я думаю, что свойство lazy
, инициализированное закрытием, будет работать:
lazy var myLabel: UILabel = {
var temporaryLabel: UILabel = UILabel()
...
return temporaryLabel
}()
Как я читал "Быстрый язык программирования". (Пример шахматной доски) закрытие оценивается только один раз).
Ответ 2
class Thingy {
init(){
println("making a new Thingy")
}
}
var thingy = {
Thingy();
}()
println("\(self.thingy)")
println("\(self.thingy)")
Сообщение журнала "Создание нового Thingy" появляется только один раз, доказывая, что был создан только один Thingy - закрытие было вызвано только один раз, а именно для инициализации этого свойства. Это эффективно то, что вы описываете. Все, что вам нужно сделать, это добавить еще к закрытию, чтобы настроить его на возвращаемый объект.
Если вы создадите var @lazy
и закомментируете утверждения println
, то Thingy не создается, доказывая, что лень делает то, что он предназначен; вы можете опустить это, однако, поскольку вы знаете, что на самом деле этикетка на самом деле всегда понадобится на ранней стадии. Точка @lazy
заключается в том, чтобы не допустить, чтобы замыкание вызывалось, пока не будет вызван геттер, но вы всегда будете называть геттер так, чтобы в вашей ситуации было бессмысленно.
Ответ 3
Это в значительной степени версия Swift как пример ObjectiveC. (упрощено использование Int
вместо представления)
class Foo {
var _value: Int?
var value: Int {
get {
if !_value {
_value = 123
}
return _value!
}
}
}
Foo().value //-> 123
Хотя это не очень красиво.
Ответ 4
Apple, похоже, делает это по-другому... Если я создам новый проект в Xcode и добавлю Core Data, там пример его в AppDelegate.swift
:
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application model.
var managedObjectModel: NSManagedObjectModel {
if !_managedObjectModel {
let modelURL = NSBundle.mainBundle().URLForResource("MyApp", withExtension: "momd")
_managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
}
return _managedObjectModel!
}
var _managedObjectModel: NSManagedObjectModel? = nil
Хотя, это читается мне, поскольку переменная создается при инициализации, однако просто читается впоследствии, а @lazy
кажется более приятной. Любые мысли?
Итак, я пробовал это:
class TestClass {
@lazy var myLabel : UILabel = {
var temporaryLabel : UILabel = UILabel()
return temporaryLabel
}()
var testLabel: UILabel {
if !_testLabel {
_testLabel = UILabel()
}
return _testLabel!
}
var _testLabel: UILabel? = nil
func test () {
println(myLabel)
println(self.testLabel)
}
}
И оба действительно созданы лениво. Поскольку @bradlarson указывает на Twitter:
@runmad Единственное, что сохраняет ваш подход, - это только чтение состояние имущества. @lazy не может использоваться с let, что является проблема.
Ответ 5
Так же, как вариант ответа Christian Otkjær, также можно назначить метод класса для @lazy var:
class MyClass {
@lazy var myLabel : UILabel = MyClass.newLabel()
class func newLabel() -> UILabel {
var temporaryLabel : UILabel = UILabel()
...
return temporaryLabel
}
}
Это фактически то же самое, что использование замыкания, но в случае, если в замыкании слишком много строк кода, это возможность поместить этот код в метод класса в другое место после объявления всех свойств и методов инициализации.
Ответ 6
Вы можете предоставить закрытие переменной @lazy, чтобы объявить, как она должна быть создана:
class Blah {
@lazy var label: () -> UILabel = {
var view:UILabel = UILabel();
//Do stuff here
return view;
}
}
Ответ 7
Swift 3.0
Я предпочитаю этот встроенный стиль.
lazy var myLabel: UILabel = self.createMyLabel()
private func createMyLabel() -> UILabel {
let mylabel = UILabel()
// ...
return mylabel
}