By Lukas Köhl


2014-09-15 18:16:30 8 Comments

I want a picture to move to the bottom. If I press a button the pic should move down by 1.

I added the picture 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 function "fahren" to move the picture down by 1.

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

So my problem is: I get several errors with these corX and corY thing. Without them it works perfectly but than its like a single-use button. The errors are: ViewController.Type does not have a member named corX and ViewController.Type does not have a member names panzer Where I get the errors I made // to show in which lines.

PS: I use 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);
    }
}

4 comments

@CrazyPro007 2018-05-19 16:53:05

//
//  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

@pkamb 2017-02-09 08:12:54

Your dependent property needs to be:

  1. lazy
  2. Have an explicit : Type
  3. 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'

@Honey 2017-05-03 16:09:40

I'm addressing the title of the question:

Both lazy and computed properties help you deal with when the initial value for a property is not known until after the object is initialized. But there are some differences. I've highlighted the differences with bold.

If you simply need to initialize a variable after some other variable(s) is initialized then you should use lazy ie if the point is to simply add a delay (so all required properties get initialized before) then using lazy is the right way to go for it.

But if you need to constantly change a variable based on another, then you need a computed property that would work both ways:

  • if the computed property set then it sets the variables its related stored properties
  • if the stored properties are set (or are reset again) then it will trigger a change in then computed property.

if you change the lazy property's value it won't affect the storied properties that it was based on. see here


A good example for using a lazy property would be that once you have firstName & lastName then you would lazily instantiate a fullName and likely you would never change the firstName lastName of your object your fullName is a onetime only... Or perhaps something that can only be done by lazy properties is that up until you don't access the property it won't ever get initialized, therefore this would decrease the initialization load of your class. Loading a heavy calculation.

Additionally using the lazy will signal to other developers: "Hey first go read about the other properties and understand what they are...then come to this lazy property...since the value of this is based on them + this is likely a heavy computation that shouldn't be accessed too early..."

As for computed 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 your Fahrenheit value.

As a result computed property would add extra computation...and if your computation is very simple and isn't called too frequently then it's nothing to worry about but if it get's called too often or is very CPU-consuming then it might be better to think of other options...

@matt 2014-09-15 20:55:26

@MartinR has pointed out the major issue here:

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

The problem is that a Swift default initializer cannot refer to the value of another property, because at the time of initialization, the property doesn't exist yet (because the instance itself doesn't exist yet). Basically, in panzer's default initializer you are implicitly referring to self.corX and self.corY - but there is no self because self is exactly what we are in the middle of creating.

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

That's legal because panzer doesn't get initialized until later, when it is first referred to by your actual code. By that time, self and its properties exist.

@Martin R 2014-09-15 21:06:36

Have you tried to compile that? First, it is lazy without @ in the current Xcode version, and even then I still get the same error message.

@matt 2014-09-16 01:13:24

@MartinR Good call. All fixed now!

@Mike S 2014-09-16 02:42:03

@matt I still get an error with that change: 'ViewController -> () -> ViewController!' does not have a member named 'corX'

@matt 2014-09-16 03:43:39

@MikeS It sounds like you typed it rather than copying and pasting. You mustn't leave anything out. For example if you omit the UIImageView type declaration you'll get that error. Or if you omit the lazy declaration you'll get that error. It is all necessary. Copy and paste right out of your browser into your code. It compiles just fine in the current version of Xcode (Xcode 6 GM).

@kelin 2017-06-27 21:06:52

This solution doesn't work. I have similar error trying to init label height constant using font constant. If I change height declaration to lazy var I will still be getting the same "Can't use instance member" error. Downvoted to prevent misleading.

@matt 2017-06-29 17:20:33

@kelin You can downvote if you like, but I assure you my answer works for the question that it answers. If you have a different problem, wouldn't it be better to ask a question about that than to assume I'm wrong when I'm not?

@kelin 2017-06-30 09:45:34

@matt, your instructions don't work, just accept it. Only pkamb tells about 3 conditions that should be met to remove the compiler error: lazy, .self and : Type. Although you used : Type you didn't tell that this is important. And you answer is much longer and harder to read. I think it isn't fair that it has more upvotes.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] How to detect tableView cell touched or clicked in swift

1 Answered Questions

4 Answered Questions

[SOLVED] Swift Error - Use of undeclared type 'cell' - Collection View

18 Answered Questions

0 Answered Questions

UIScrollView cannot display image either in Portrait or Landscape mode

  • 2015-06-03 10:13:43
  • MilkBottle
  • 241 View
  • 0 Score
  • 0 Answer
  • Tags:   ios swift

9 Answered Questions

[SOLVED] How to "add existing frameworks" in Xcode 4?

1 Answered Questions

Set image background for view with 3 images sizes

  • 2015-06-22 15:08:07
  • MilkBottle
  • 93 View
  • 0 Score
  • 1 Answer
  • Tags:   swift

1 Answered Questions

[SOLVED] Why don't use var at the beginning?

  • 2015-04-20 10:46:04
  • chipbk10
  • 264 View
  • 0 Score
  • 1 Answer
  • Tags:   ios swift

1 Answered Questions

Active buttons in scrollview

2 Answered Questions

[SOLVED] Display UIImageView in full screen (320*480)

Sponsored Content