Cómo inicializar propiedades que dependen unas de otras


Quiero que una imagen se mueva hacia abajo. Si presiono un botón, la foto se moverá hacia abajo en 1.

He añadido la imagen y un botón:

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

Al menos dije en función "fahren" para mover la imagen hacia abajo por 1.

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

Así que mi problema es: tengo varios errores con estos corX y corY cosa. Sin ellos funciona perfectamente, pero que es como un botón de un solo uso. Los errores son: ViewController.Type no tiene un miembro llamado corX y ViewController.El tipo no tener un nombre de miembro panzer Donde obtengo los errores que cometí / / para mostrar en qué líneas.

PD: Uso Xcode Beta5

Aquí está el código completo sin nada más:

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);
    }
}
Author: AmitaiB, 2014-09-15

4 answers

@MartinR ha señalado el problema principal aquí:

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

El problema es que un inicializador predeterminado de Swift no puede hacer referencia al valor de otra propiedad, porque en el momento de la inicialización, la propiedad no existe todavía (porque la instancia en sí no existe todavía). Básicamente, en el inicializador predeterminado de panzer se está refiriendo implícitamente a self.corX y self.corY, pero no hay self porque self es exactamente lo que estamos creando.

Una solución es haga que el inicializador sea perezoso:

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

Eso es legal porque panzer no se inicializa hasta más tarde, cuando se refiere por primera vez por su código real. En ese momento, self y sus propiedades existen.

 52
Author: matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-16 03:41:10

Su propiedad dependiente debe ser:

  1. lazy
  2. Tener un : Type
  3. Use self. para acceder a otras propiedades

Ejemplo:

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'
 6
Author: pkamb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-13 18:45:55

Me dirijo al título de la pregunta:

Tanto las propiedades perezosas como las calculadas le ayudan a lidiar con cuando el valor inicial de una propiedad es no conocido hasta después de que el objeto se inicializa. Pero hay algunas diferencias. He resaltado las diferencias con negrita.

Si simplemente necesita inicializar una variable después de que se inicialice otra(s) variable (s), debe usar lazy ie si el punto es simplemente agregar un retraso (para que todas las propiedades requeridas obtengan inicializado antes), entonces usar lazy es la forma correcta de hacerlo.

Pero si necesita cambiar constantemente una variable basada en otra, entonces necesita una propiedad calculada que funcione en ambos sentidos :

  • si la propiedad calculada establece entonces establece las variables sus propiedades almacenadas relacionadas
  • si se establecen las propiedades almacenadas (o se restablecen de nuevo ), se activará un cambio en el entonces calculado propiedad.

si cambia el valor de la propiedad lazy, no afectará a las propiedades con historia en las que se basó. ver aquí


Un buen ejemplo para usar una propiedad perezosa sería que una vez que tenga firstName & lastName entonces instanciaría perezosamente un fullName y probablemente nunca cambiaría el FirstName LastName de su objeto su nombre completo es solo una vez... O tal vez algo que solo se puede hacer por lazy propiedades es que hasta que no acceda a la propiedad nunca se inicializará, por lo tanto esto disminuiría la carga de inicialización de su clase. Cargando un cálculo pesado .

Además, usando el lazy señal a otros desarrolladores: "Oye primero lee sobre las otras propiedades y entiende lo que son...entonces ven a esta propiedad perezosa...dado que el valor de esto se basa en ellos + esto es probablemente un cálculo pesado que no se debe acceder demasiado temprano..."

En cuanto a la propiedad calculada, un buen ejemplo sería si establece la temperatura en Fahrenheit entonces también desea que su temperatura celsius cambie su valor...y si establece la temperatura celsius , entonces nuevamente desea cambiar su valor Fahrenheit .

Como resultado, la propiedad computada agregaría cómputo adicional...y si su computación es muy simple y no se llama con demasiada frecuencia, entonces no es nada de qué preocuparse, pero si get llama demasiado a menudo o es muy CPU-consumo entonces podría ser mejor pensar en otras opciones...

 0
Author: Honey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:24
//
//  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()

Muestra de Xcode

 0
Author: CrazyPro007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-19 16:53:05