How to initialize properties that depend on each other

I want the image to move to the bottom. If I press the button, fig. Should move down by 1.

I added an image and a button:

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) } 

At least I said in the "fahren" function to move the snapshot by 1.

 func fahren(){ corY += 1 panzer.frame = CGRectMake(corX, corY, 30, 40) // self.view.addSubview(panzer); } 

So my problem is: I get a few errors with these corX and corY. Without them, it works great, and not like a one-time button. Errors: ViewController.Type does not have a member named corX and ViewController.Type does not have a panzer member name. Where do I get the errors that I made // to show in which lines.

PS: I am using Xcode Beta5

Here's the complete code without anything else:

 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); } } 
+73
xcode swift frame cgrectmake
Sep 15 '14 at 18:16
source share
4 answers

@MartinR pointed out the main problem:

 var corX = 0 var corY = 0 var panzer = UIImageView(frame: CGRectMake(corX, corY, 30, 40)) 

The problem is that, by default, the Swift initializer cannot refer to the value of another property, because the property does not exist during initialization (since the instance itself does not exist). Basically, in the default panzer initializer, you implicitly refer to self.corX and self.corY - but there is no self , because self is exactly what we are in the middle of creation.

One workaround is to make the initializer lazy:

 class ViewController: UIViewController { var corX : CGFloat = 0 var corY : CGFloat = 0 lazy var panzer : UIImageView = UIImageView(frame: CGRectMake(self.corX, self.corY, 30, 40)) // ... } 

This is legal because panzer not initialized until a later time, when it is first mentioned by your actual code. By this time, self and its properties exist.

+63
Sep 15 '14 at 20:55
source share

Your dependent property should be:

  • lazy
  • Have Explicit : Type
  • Use self. to access other properties

Example:

 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' 
+9
Feb 09 '17 at 8:12
source share

I turn to the title of the question:

Both lazy and computed properties will help you cope when the initial value of the property is unknown until the object is initialized. But there are some differences. I highlighted in bold.

If you just need to initialize the variable after some other variable (s) have been initialized, you should use lazy , that is, if the point is to just add a delay (so that all the necessary properties are initialized earlier), then use lazy is the right way for this.

But if you need to constantly change a variable based on another, then you need to calculate a property that will work in both directions :

  • if the computed property is set, it sets the variables their associated stored properties
  • if the stored properties are set (or reset again), then this will cause a change in the computed property.

, if you change the value of lazy property, this will not affect the floor properties on which it was based. see here




A good example of using a lazy property would be if you have firstName and lastName , then you lazily create an instance of fullName and most likely you will never change the name of the firstName lastName of your object. Your full name is a one-time only ... Or maybe something that can only be done using the lazy properties is that until you access the property , it will never be initialized , therefore, this will reduce the initialization burden of your class. The calculation load is heavy .

In addition, using lazy will signal to other developers: "Hey, first read about other properties and understand that they ... then come to this lazy property ... as the meaning of this is based on them + this is probably a difficult calculation to which can't access too soon ... "

As with the calculated property, a good example would be if you set the temperature to Fahrenheit, then you also want your Celsius temperature to change its value ... and if you set the Celsius temperature, then again you want to change the Fahrenheit value.

As a result, the computed property will add additional calculations ... and if your calculation is very simple and is not called too often, then there is nothing to worry about, but if it is called too often or the processor consumes very much, then it might be better to think about other options ...

0
May 03 '17 at 16:09
source share
 // // 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() 

Xcode sample

0
May 19 '18 at 16:53
source share



All Articles