如何初始化相互依赖的属性

时间:2022-04-12 12:52:00

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

我想要一幅画在底部。如果我按下一个按钮,图片应该向下移动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.

至少我在函数“fahren”中说过要把照片往下移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.

我的问题是,corX和corY有几个错误。没有它们,它可以完美地工作,但它不像一个单一使用的按钮。错误:ViewController。类型没有名为corX和ViewController的成员。类型中没有成员名称panzer,在那里我得到了我所犯的错误//以显示在哪些行中。

PS: I use Xcode Beta5

PS:我用的是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 个解决方案

#1


50  

@MartinR has pointed out the major issue here:

@MartinR指出了这里的主要问题:

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.

问题是,Swift默认初始化器不能引用另一个属性的值,因为在初始化时,属性还不存在(因为实例本身还不存在)。基本上,在panzer的默认初始化器中,你指的是self。corX和自我。科里-但没有自我,因为自我正是我们正在创造的东西。

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.

这是合法的,因为panzer直到稍后才被初始化,当它第一次被实际代码引用时。到那时,自我和它的属性就存在了。

#2


6  

Your dependent property needs to be:

你的附属财产必须为:

  1. lazy
  2. 懒惰的
  3. Have an explicit : Type
  4. 有一个明确的:类型
  5. Use self. to access other properties
  6. 使用自我。访问其他属性

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'

#3


0  

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.

如果您只是需要在初始化其他变量之后初始化一个变量,那么您应该使用lazy ie,如果要点是简单地添加一个延迟(因此所有必需的属性都在初始化之前),那么使用lazy是正确的方法。

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

如果您更改了lazy属性的值,它将不会影响它所基于的故事属性。在这里看到的


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.

使用惰性属性的一个很好的例子是,一旦你有了firstName和lastName,你就会惰性实例化一个fullName,而且很可能你永远不会改变你的对象的姓,你的全名是一次性的……或者可能只有惰性属性才能完成的事情是,直到你不访问属性时它才会被初始化,因此这会减少类的初始化负载。加载一个沉重的计算。

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..."

此外,使用lazy将向其他开发人员发出信号:“嘿,先去看看其他属性,了解它们是什么……”然后来到这个懒惰的地方……因为它的值是基于它们+这很可能是一个繁重的计算,不应该太早访问……

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

因此计算属性会增加额外的计算量……如果你的计算非常简单,而且没有被频繁调用,那也没什么好担心的,但是如果它被频繁调用或者非常消耗cpu,那么最好考虑其他选项……

#4


0  

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

如何初始化相互依赖的属性

#1


50  

@MartinR has pointed out the major issue here:

@MartinR指出了这里的主要问题:

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.

问题是,Swift默认初始化器不能引用另一个属性的值,因为在初始化时,属性还不存在(因为实例本身还不存在)。基本上,在panzer的默认初始化器中,你指的是self。corX和自我。科里-但没有自我,因为自我正是我们正在创造的东西。

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.

这是合法的,因为panzer直到稍后才被初始化,当它第一次被实际代码引用时。到那时,自我和它的属性就存在了。

#2


6  

Your dependent property needs to be:

你的附属财产必须为:

  1. lazy
  2. 懒惰的
  3. Have an explicit : Type
  4. 有一个明确的:类型
  5. Use self. to access other properties
  6. 使用自我。访问其他属性

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'

#3


0  

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.

如果您只是需要在初始化其他变量之后初始化一个变量,那么您应该使用lazy ie,如果要点是简单地添加一个延迟(因此所有必需的属性都在初始化之前),那么使用lazy是正确的方法。

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

如果您更改了lazy属性的值,它将不会影响它所基于的故事属性。在这里看到的


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.

使用惰性属性的一个很好的例子是,一旦你有了firstName和lastName,你就会惰性实例化一个fullName,而且很可能你永远不会改变你的对象的姓,你的全名是一次性的……或者可能只有惰性属性才能完成的事情是,直到你不访问属性时它才会被初始化,因此这会减少类的初始化负载。加载一个沉重的计算。

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..."

此外,使用lazy将向其他开发人员发出信号:“嘿,先去看看其他属性,了解它们是什么……”然后来到这个懒惰的地方……因为它的值是基于它们+这很可能是一个繁重的计算,不应该太早访问……

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

因此计算属性会增加额外的计算量……如果你的计算非常简单,而且没有被频繁调用,那也没什么好担心的,但是如果它被频繁调用或者非常消耗cpu,那么最好考虑其他选项……

#4


0  

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

如何初始化相互依赖的属性

相关文章