Ich möchte, dass ein Bild nach unten verschoben wird. Wenn ich einen Knopf drücke, sollte sich das Bild um 1 nach unten bewegen.
Ich habe das Bild und einen Button hinzugefügt:
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)
}
Zumindest sagte ich in Funktion "fahren", um das Bild um 1 nach unten zu verschieben.
func fahren(){
corY += 1
panzer.frame = CGRectMake(corX, corY, 30, 40) //
self.view.addSubview(panzer);
}
Mein Problem ist also: Ich bekomme mehrere Fehler mit diesen corX- und corY-Dingen. Ohne sie funktioniert es perfekt, aber es ist wie ein Einwegknopf. Die Fehler sind: ViewController.Type hat kein Mitglied mit dem Namen corX und ViewController.Type hat kein Mitglied mit dem Namen panzer. Woher bekomme ich die Fehler, die ich // gemacht habe, um anzuzeigen, in welchen Zeilen.
PS: Ich benutze Xcode Beta5
Hier ist der vollständige Code ohne irgendetwas anderes:
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);
}
}
xcode
swift
frame
cgrectmake
Lukas Köhl
quelle
quelle
var corX = 0
befindet er sich nicht auf der obersten Ebene derclass
Deklaration.Antworten:
@MartinR hat hier auf das Hauptproblem hingewiesen:
var corX = 0 var corY = 0 var panzer = UIImageView(frame: CGRectMake(corX, corY, 30, 40))
Das Problem ist, dass ein Swift-Standardinitialisierer nicht auf den Wert einer anderen Eigenschaft verweisen kann, da die Eigenschaft zum Zeitpunkt der Initialisierung noch nicht vorhanden ist (da die Instanz selbst noch nicht vorhanden ist). Grundsätzlich
panzer
beziehen Sie sich im Standardinitialisierer implizit aufself.corX
undself.corY
- aber es gibt keine,self
weilself
genau das ist, was wir gerade erstellen.Eine Problemumgehung besteht darin, den Initialisierer faul zu machen:
class ViewController: UIViewController { var corX : CGFloat = 0 var corY : CGFloat = 0 lazy var panzer : UIImageView = UIImageView(frame: CGRectMake(self.corX, self.corY, 30, 40)) // ... }
Das ist legal, da
panzer
es erst später initialisiert wird, wenn es zum ersten Mal von Ihrem eigentlichen Code referenziert wird. Zu diesem Zeitpunktself
und seine Eigenschaften existieren.quelle
lazy
ohne@
in der aktuellen Version von Xcode, und selbst dann ich immer noch die gleichen Fehlermeldung.'ViewController -> () -> ViewController!' does not have a member named 'corX'
lazy
,.self
und: Type
. Obwohl Sie verwendet haben, haben: Type
Sie nicht gesagt, dass dies wichtig ist. Und Ihre Antwort ist viel länger und schwerer zu lesen. Ich denke, es ist nicht fair, dass es mehr positive Stimmen gibt.Ihr abhängiges Eigentum muss sein:
lazy
: Type
self.
diese Option, um auf andere Eigenschaften zuzugreifenBeispiel:
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'
quelle
Ich spreche den Titel der Frage an:
Beide faul und berechneten Eigenschaften helfen Sie befassen sich mit , wenn der Anfangswert für eine Eigenschaft ist nicht bekannt , bis , nachdem das Objekt initialisiert wird. Es gibt jedoch einige Unterschiede. Ich habe die Unterschiede fett hervorgehoben.
Wenn Sie lediglich eine Variable initialisieren müssen, nachdem eine andere Variable initialisiert wurde, sollten Sie Folgendes verwenden:
lazy
Wenn Sie lediglich eine Verzögerung hinzufügen möchten (damit alle erforderlichen Eigenschaften zuvor initialisiert werden), ist die Verwendung von Lazy der richtige Weg es.Wenn Sie jedoch eine Variable basierend auf einer anderen ständig ändern müssen, benötigen Sie eine berechnete Eigenschaft, die in beide Richtungen funktioniert :
Wenn Sie den Wert der Lazy-Eigenschaft ändern, wirkt sich dies nicht auf die gespeicherten Eigenschaften aus, auf denen sie basiert. siehe hier
Ein gutes Beispiel für die Verwendung einer Lazy-Eigenschaft wäre, dass Sie, sobald Sie
firstName
&lastName
dann haben, einen faul instanziierenfullName
und wahrscheinlich niemals den Vornamen Nachnamen Ihres Objekts ändern würden. Ihr vollständiger Name ist nur einmalig ... oder vielleicht etwas, das nur getan werden kann Nachlazy
Eigenschaften wird sie so lange nicht initialisiert , bis Sie nicht auf die Eigenschaft zugreifen. Daher würde dies die Initialisierungslast Ihrer Klasse verringern . Laden einer schweren Berechnung.Zusätzlich wird die Verwendung
lazy
wird das Signal an andere Entwickler: „Hey zuerst über die anderen Eigenschaften als gelesen und verstehen , was sie sind ... dann auf diese faul Eigenschaft kommen ... da der Wert dieser auf ihnen basiert + dies ist wahrscheinlich eine schwere Berechnung, auf die nicht zu früh zugegriffen werden sollte ... "Ein gutes Beispiel für die berechnete Eigenschaft wäre, wenn Sie die Temperatur auf Fahrenheit einstellen, dann möchten Sie auch, dass Ihre Celsius- Temperatur ihren Wert ändert ... und wenn Sie die Celsius- Temperatur einstellen , möchten Sie erneut Ihren Fahrenheit- Wert ändern .
Infolgedessen würde die berechnete Eigenschaft zusätzliche Berechnungen hinzufügen ... und wenn Ihre Berechnung sehr einfach ist und nicht zu häufig aufgerufen wird, besteht kein Grund zur Sorge, aber wenn sie zu oft aufgerufen wird oder sehr CPU-aufwendig ist, ist sie möglicherweise besser an andere Möglichkeiten denken ...
quelle
// // 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()
quelle