unavailable cgrectgetwidth cgpointmake xcode swift frame cgrectmake

xcode - cgrectgetwidth - cgrectmake swift 4



Cómo inicializar propiedades que dependen unas de otras (4)

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

Agregué 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 la 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); }

Entonces mi problema es: recibo varios errores con estos corX y corY. Sin ellos, funciona perfectamente, pero es como un botón de un solo uso. Los errores son: ViewController.Type no tiene un miembro llamado corX y ViewController.Type no tiene un nombre de miembro panzer Donde obtengo los errores que hice // 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); } }


@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 aún no existe (porque la instancia en sí misma aún no existe). Básicamente, en el inicializador por defecto de panzer te estás refiriendo implícitamente a self.corX y self.corY , pero no existe un self porque el self es exactamente lo que estamos creando.

Una solución es hacer que el inicializador sea flojo:

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 adelante, cuando su código actual lo menciona por primera vez. En ese momento, el self y sus propiedades existen.


Me dirijo al título de la pregunta:

Las propiedades tanto perezosas como calculadas lo ayudan a lidiar cuando el valor inicial de una propiedad no se conoce 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 inicialicen otras variables, deberá usar lazy es decir, si el punto es simplemente agregar un retraso (para que todas las propiedades requeridas se inicialicen antes), entonces usar perezoso es el camino correcto a seguir. para ello.

Pero si necesita cambiar constantemente una variable en función de 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 las propiedades almacenadas están configuradas (o se restablecen nuevamente ), se activará un cambio en la propiedad calculada.

si cambia el valor del inmueble perezoso, no afectará a las propiedades históricas en las que se basó. ver here

Un buen ejemplo para usar una propiedad perezosa sería que una vez que tenga firstName y lastName entonces instanciaría perezosamente un fullName y probablemente nunca cambiaría el firstName lastName de su objeto, su fullName es solo una vez ... O quizás algo que pueda Solo lo harán las propiedades lazy , 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, usar el lazy indicará a otros desarrolladores: "Oye, primero lee sobre las otras propiedades y entiende cuáles son ... luego ve a esta propiedad perezosa ... ya que el valor de esto se basa en ellas + es probable que cálculo pesado que no se debe acceder demasiado pronto ... "

En cuanto a la propiedad calculada, un buen ejemplo sería si configuras la temperatura en Fahrenheit, luego también deseas que tu temperatura centígrafa cambie su valor ... y si estableces la temperatura celsius , entonces de nuevo quieres cambiar tu valor de Fahrenheit .

Como resultado, la propiedad calculada agregaría cómputo adicional ... y si su cálculo es muy simple y no se llama con demasiada frecuencia, entonces no es nada de qué preocuparse, pero si se llama con demasiada frecuencia o consume mucha CPU, podría ser mejor. pensar en otras opciones ...


Su propiedad dependiente debe ser:

  1. lazy
  2. Tener un explícito : Type
  3. Usa el 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''


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