Как инициализировать свойства, которые зависят друг от друга
Я хочу, чтобы изображение переместилось на дно. Если я нажму кнопку, пик должен двигаться вниз на 1.
я добавил изображение и кнопку:
var corX = 0
var corY = 0
var runter: UIButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
var image = UIImage(named: "panzerBlau.jpg");
var panzer = UIImageView(frame: CGRectMake(corX, corY, 30, 40)); //
override func viewDidLoad() {
super.viewDidLoad()
panzer.image = image; //
self.view.addSubview(panzer); //
runter.frame = CGRectMake(100, 30, 10 , 10)
runter.backgroundColor = UIColor.redColor()
view.addSubview(runter)
runter.addTarget(self, action: "fahren", forControlEvents:UIControlEvents.TouchUpInside)
}
по крайней мере, я сказал в функции "fahren", чтобы переместить изображение вниз на 1.
func fahren(){
corY += 1
panzer.frame = CGRectMake(corX, corY, 30, 40) //
self.view.addSubview(panzer);
}
Итак, моя проблема: я получаю несколько ошибок с этими corX и corY thing. Без них он работает отлично, но чем его как одноразовая кнопка. Ошибки: ViewController.Тип не имеет члена с именем corX и ViewController.Тип не имеет имени члена panzer, где я получаю ошибки, которые я сделал//, чтобы показать, в каких строках.
PS: я использую Xcode Beta5
вот полный код без чего-либо еще:
import UIKit
class ViewController: UIViewController {
var corX = 0
var corY = 0
var runter: UIButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
var image = UIImage(named: "panzerBlau.jpg");
var panzer = UIImageView(frame: CGRectMake(corX, corY, 30, 40));
override func viewDidLoad() {
super.viewDidLoad()
panzer.image = image;
self.view.addSubview(panzer);
runter.frame = CGRectMake(100, 30, 10 , 10)
runter.backgroundColor = UIColor.redColor()
view.addSubview(runter)
runter.addTarget(self, action: "fahren", forControlEvents:UIControlEvents.TouchUpInside)
}
func fahren(){
corY += 100
panzer.frame = CGRectMake(corX, corY, 30, 40)
self.view.addSubview(panzer);
}
}
4 ответа:
@MartinR указал на главную проблему здесь:
var corX = 0 var corY = 0 var panzer = UIImageView(frame: CGRectMake(corX, corY, 30, 40))
проблема в том, что инициализатор Swift по умолчанию не может ссылаться на значение другого свойства, потому что на момент инициализации свойство еще не существует (потому что сам экземпляр еще не существует). В основном, в
panzer
инициализатор по умолчанию, на который вы неявно ссылаетесьself.corX
иself.corY
, но нетself
, потому чтоself
- это именно то, что мы находимся в середине творящий.один обходной путь - сделать инициализатор ленивым:
class ViewController: UIViewController { var corX : CGFloat = 0 var corY : CGFloat = 0 lazy var panzer : UIImageView = UIImageView(frame: CGRectMake(self.corX, self.corY, 30, 40)) // ... }
что это законно, потому что
panzer
не инициализируется до тех пор, пока он не будет впервые упомянут вашим фактическим кодом. К тому времени, и его свойства.
ваше зависимое свойство должно быть:
lazy
- явный
: Type
- использовать
self.
для доступа к другим свойствампример:
let original = "foo" // Good: lazy var depend: String = self.original // Error: var noLazy: String = self.original // Error: Value of type '(NSObject) -> () -> URLData' has no member 'original' lazy var noType = self.original // Error: Value of type '(NSObject) -> () -> URLData' has no member 'original' lazy var noSelf: String = original // Error: Instance member 'original' cannot be used on type 'YourClass'
Я обращаюсь к названию вопроса:
как ленивые, так и вычисляемые свойства помогают вам справиться с тем, когда начальное значение для свойства не известно до тех пор, пока объект не будет инициализирован. Но есть и некоторые отличия. Я выделил различия жирным шрифтом.
Если вам просто нужно инициализировать переменную после инициализации некоторых других переменных, то вы должны использовать
lazy
т. е. если дело в том, чтобы просто добавить задержку (так что все требуется свойства инициализируются раньше), то использование lazy-это правильный путь для этого.но если вам нужно постоянно изменить переменную на основе другой, то вам нужно вычисленное свойство, которое будет работать обе стороны:
- если вычисленное свойство set затем он устанавливает переменные, связанные с его сохраненными свойствами
- если сохраненные свойства установлены (или сброшены снова), то он будет вызовите изменение в затем вычисленном свойстве.
если вы измените значение свойства lazy, это не повлияет на свойства storied, на которых оно было основано. смотрите здесь
хорошим примером для использования ленивого свойства было бы то, что у вас есть
firstName
&lastName
тогда вы лениво создадите экземпляр afullName
и, вероятно, вы никогда не изменили бы имя фамилия вашего объекта ваше полное имя-это только один раз... Или, возможно, то, что может быть сделано толькоlazy
свойства это до тех пор, пока вы не получите доступ к свойству он никогда не будет инициализирован, таким образом уменьшить инициализация нагрузки вашего класса. Загрузка тяжелый расчет.дополнительно использовать
lazy
будет сигнал другим разработчикам: "Эй, сначала прочитайте о других свойствах и поймите, что это такое...тогда приходите к этому ленивому свойство...поскольку значение этого основано на них + это, вероятно, тяжелое вычисление, к которому не следует обращаться слишком рано..."что касается вычисляемого свойства, хорошим примером будет, если вы установите температуру в по Фаренгейту тогда Вы тоже хотите ваш Цельсия температуры, чтобы изменить его значение...и если вы поставили Цельсия температуры, затем снова вы хотите изменить свой по Фаренгейту значение.
в результате вычисленное свойство добавит дополнительные вычисления...и если ваше вычисление очень простое и не вызывается слишком часто, то беспокоиться не о чем, но если оно вызывается слишком часто или очень потребляет процессор, тогда лучше подумать о других вариантах...
// // ViewController.swift // // Created by Shivank Agarwal on 19/05/18. // Copyright © 2018 Shivank Agarwal. All rights reserved. // import UIKit class ViewController: UIViewController { var corX = 0 var corY = 0 var runter: UIButton = UIButton() var image = UIImage(named: "panzerBlau.jpg") var panzer = UIImageView() override func viewDidLoad() { super.viewDidLoad() panzer.image = image; self.view.addSubview(panzer); panzer.frame = CGRect(x: CGFloat(corX), y: CGFloat(corY), width: 30, height: 40) runter.backgroundColor = UIColor.red view.addSubview(runter) view.addSubview(panzer) runter.addTarget(self, action: Selector(("fahren")), for:UIControlEvents.touchUpInside) } private func fahren(){ corY += 100 } private func updatePanzerFrame(){ panzer.frame = CGRect(x: CGFloat(corX), y: CGFloat(corY), width: 30, height: 40) } } Note: Do not add panzer imageView every time when user tap only add it on viewDidLoad()