2014-11-25 16 views
20

Da Objekte Referenztypen sind, keine Werttypen, wenn Sie UIView gleich einem anderen UIView setzen, sind die Ansichten das gleiche Objekt. Wenn Sie einen ändern, ändern Sie auch den anderen.Erstellen einer Kopie einer UIView in Swift

Ich habe eine interessante Situation, wo ich eine UIView als Subview in einer anderen Ansicht hinzufügen möchte, dann mache ich einige Änderungen, und diese Änderungen sollten nicht das Original UIView beeinflussen. Wie kann ich eine Kopie von UIView erstellen, damit ich sicherstellen kann, dass ich diese Kopie als Unteransicht anstelle eines Verweises auf das Original UIView hinzufüge?

Beachten Sie, dass ich die Ansicht auf die gleiche Weise, wie das Original erstellt wurde, nicht neu erstellen kann, brauche ich eine Möglichkeit, eine Kopie mit einem beliebigen UIView Objekt zu erstellen.

Antwort

10

Sie können ein Objekt nicht beliebig kopieren. Nur Objekte, die das Protokoll NSCopying implementieren, können kopiert werden.

Allerdings gibt es eine Abhilfe: Da UIView s auf die Festplatte serialisiert werden kann (zB von einem XIB zu laden), könnten Sie NSKeyedArchiver und NSKeyedUnarchiver verwenden, um eine serialisierte NSData zur Beschreibung Ihrer Ansicht zu erstellen, dann Deserialisieren das wieder Erhalte ein unabhängiges, aber identisches Objekt.

+0

@DannyBravo Wo Sie das her? Meine UIView.h deklariert nur die Konformität zu NSCoding, UIA-Aufruf, UIA-Aufruf, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem und CALayerDelegate. Kein NSCopy da drinnen soweit ich sehen kann. – uliwitness

+0

Sie haben völlig Recht, ich habe mich ein wenig gemischt. Ich entferne meine Antwort. –

3

Ich denke, dass Sie Ihre UIView mit einer .nib verknüpfen und nur eine neue erstellen sollten.

Die Eigenschaft wird nicht die gleiche sein, aber Sie behalten Aussehen und Methoden.

+0

Das ist auch ein guter Ansatz. Wenn Sie bereits ein XIB haben, in dem Sie das Objekt definieren, und Sie hauptsächlich über die korrekte Einrichtung besorgt sind und die Attribute, die Sie daran ändern, nur wenige sind, können Sie das XIB einfach ein zweites Mal laden (Sie können XIBs mit eine einzelne frei schwebende Ansicht in ihnen). – uliwitness

+0

wenn es xib basiert. – eric

1

Sie müssen Muster Prototyp

Beispiel des Prototyps verwenden:

class ThieveryCorporationPersonDisplay { 
    var name: String? 
    let font: String 

    init(font: String) { 
     self.font = font 
    } 

    func clone() -> ThieveryCorporationPersonDisplay { 
     return ThieveryCorporationPersonDisplay(font:self.font) 
    } 
} 

Ein Beispiel Prototyp mit:

let Prototype = ThieveryCorporationPersonDisplay(font:"Ubuntu") 

let Philippe = Prototype.clone() 
Philippe.name = "Philippe" 

let Christoph = Prototype.clone() 
Christoph.name = "Christoph" 

let Eduardo = Prototype.clone() 
Eduardo.name = "Eduardo" 
60

Sie können eine UIView Erweiterung machen. Im folgenden Codebeispiel gibt die Funktion copyView ein AnyObject zurück, sodass Sie jede Unterklasse einer UIView, , dh UIImageView, kopieren können. Wenn Sie nur UIView kopieren möchten, können Sie den Rückgabetyp in UIView ändern.

//MARK: - UIView Extensions 

extension UIView 
{ 
    func copyView<T: UIView>() -> T { 
     return NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: self)) as! T 
    } 
} 

Beispiel Nutzung:

let sourceView = UIView() 
let copiedView: UIView = sourceView.copyView() 
+2

Dies sollte die akzeptierte Antwort sein –

+1

Wie ist das eine Factory-Methode auf UIView? –

+0

Sehr nützlich! Vielen Dank! – Glenn

2

Diese Antwort zeigt, wie zu tun, was @uliwitness vorgeschlagen. Das heißt, Sie erhalten ein identisches Objekt, indem Sie es archivieren und dann wieder auslagern. (Es ist auch das, was im Grunde Ivan Porkolab in seiner Antwort tat, aber in einem besser lesbaren Format, denke ich.)

let myView = UIView() 

// create an NSData object from myView 
let archive = NSKeyedArchiver.archivedData(withRootObject: myView) 

// create a clone by unarchiving the NSData 
let myViewCopy = NSKeyedUnarchiver.unarchiveObject(with: archive) as! UIView 

Hinweise

  • dearchiviert die Daten erstellt ein Objekt vom Typ AnyObject. Wir haben as! UIView verwendet, um es wieder in ein UIView zu schreiben, da wir wissen, dass es das ist. Wenn unsere Ansicht eine UITextView wäre, könnten wir sie eingeben as! UITextView.
  • Die myViewCopy hat nicht mehr eine übergeordnete Sicht.
  • Some people erwähnen einige Probleme bei der Arbeit mit UIImage. Siehe jedoch this und this Antwort.

zu Swift aktualisiert zu schaffen seine 3,0

+0

Ich implementierte dies und für eine Sekunde dachte ich, es funktioniert. Aber ich kopiere eine UIView, die Subviews hat und das Ergebnis, das ich bekomme, sind die Subviews, aber nicht die View selbst. Ich habe gesehen, wie die Ansichtshierarchie debuggt wurde. Die Ansicht, dass ich kopiere, ist ein IBOutlet anstelle von 'UIView()'. Klingt das bekannt? –

+0

Es tut mir leid. Beim Debuggen etwas mehr ist, dass in der kopierten Ansicht ich 'view.top = view.bottom' als Einschränkung bekomme und deshalb sehe ich es nicht in der Ansichtshierarchie. –

0

Eine Zugabe Lösung könnte nur ein neues UIView und dann über alle kritischen Eigenschaften zu kopieren. Dies mag im OP nicht funktionieren, aber es könnte sehr gut für andere Fälle funktionieren.

Zum Beispiel mit einem UITextView, wahrscheinlich alles, was Sie brauchen würden, ist der Rahmen und die zugeschrieben Text:

let textViewCopy = UITextView(frame: textView.frame) 
textViewCopy.attributedText = textView.attributedText 
Verwandte Themen