Kann UIView kopiert werden?

81

Einfach so:

UIView* view2 = [view1 copy]; // view1 existed

Dies führt dazu, dass der Simulator diese App nicht starten kann.

Versuchen Sie zu behalten,

UIView* view2 = [view1 retain]; // view1 existed
// modify view2 frame etc

Alle Änderungen an view2gelten view1, ich verstehe, dass view2die gleichen Speicher mit teilen view1.

Warum kann nicht UIViewkopiert werden? Was ist der Grund?

Wald
quelle

Antworten:

33

Ihre App stürzt wahrscheinlich ab mit:

 [UIView copyWithZone:]: unrecognized selector sent to instance 0x1c6280

Der Grund dafür ist, dass UIView das Kopierprotokoll nicht implementiert und daher copyWithZonein UIView kein Selektor vorhanden ist.

Engin Kurutepe
quelle
10
Was muss ich tun, um die Kopie von UIView zu implementieren?
Satyam
1
Wenn Sie also eine bestimmte Kombination von UIView haben und diese mehrmals verwenden möchten, müssen Sie eine solche UIView in Unterklassen unterteilen?
Anonym Weiß
Ja, Unterklassen oder Kategorien mit Factory-Methoden auf Klassenebene, die vorkonfigurierte Instanzen dieser Ansicht zurückgeben.
Engin Kurutepe
162

Dies könnte für Sie funktionieren ... Archivieren Sie die Ansicht und entfernen Sie die Archivierung direkt danach. Dies sollte Ihnen eine tiefe Kopie einer Ansicht geben:

id copyOfView = 
[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalView]];
j2emanue
quelle
1
Das scheint ein bisschen wie ein Hack zu sein, funktioniert aber wie ein Traum. Die Antwort von ssj unten ist im Grunde ein 'Kopierkonstruktor', der für kleine Klassen in Ordnung ist. Sie können vielleicht die obj-c-Laufzeit verwenden, um alle Eigenschaften auf einmal zu kopieren. Dies ist noch einfacher;)
Patrick Borkowicz
1
Dies funktioniert, scheint aber selbst für triviale Sichtbäume sehr langsam zu sein.
Ian Newson
6
Es funktioniert, aber Vorsicht! Es werden keine Werte für @IBOutlets festgelegt, alle sind nach dem "Kopieren"
gleich
1
Dies scheint UIImageViews zu ignorieren :(
Iulian Onofrei
1
Danke, funktioniert super! Bitte beachten Sie auch, dass die kopierte Ansicht keine Übersicht (übergeordnet), keine Einschränkungen und keine Gestenerkenner hat (falls die übergeordnete Ansicht vorhanden war).
Sajjon
25

Sie können eine UIView-Erweiterung erstellen. Im folgenden Beispiel eines schnellen Snippets gibt die Funktion copyView ein AnyObject zurück, sodass Sie eine beliebige Unterklasse eines UIView, dh UIImageView , kopieren können. Wenn Sie nur UIViews 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
       }
    }

Anwendungsbeispiel:

let sourceView = UIView()
let copiedView = sourceView.copyView()
Ivan Porkolab
quelle
1
Danke, funktioniert super! Bitte beachten Sie auch, dass die kopierte Ansicht keine Übersicht (übergeordnet), keine Einschränkungen und keine Gestenerkenner hat (falls die übergeordnete Ansicht vorhanden war).
Sajjon
6

für swift3.0.1:

extension UIView{
 func copyView() -> AnyObject{
    return NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: self))! as AnyObject
 }
}
Sour LeangChhean
quelle
1

UIViewimplementiert das NSCopingProtokoll nicht, siehe die Deklaration in UIView.h :

@interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusEnvironment>

Wenn wir also eine copyähnliche Methode haben möchten, müssen wir das NSCopingProtokoll in einer Kategorie oder so implementieren .

HongchaoZhang
quelle
-6

Sie können eine Methode wie folgt erstellen:

-(UILabel*)copyLabelFrom:(UILabel*)label{
//add whatever needs to be copied
UILabel *newLabel = [[UILabel alloc]initWithFrame:label.frame];
newLabel.backgroundColor = label.backgroundColor;
newLabel.textColor = label.textColor;
newLabel.textAlignment = label.textAlignment;
newLabel.text = label.text;
newLabel.font = label.font;

return [newLabel autorelease];

}

Dann können Sie Ihren ivar auf den Rückgabewert setzen und ihn wie folgt beibehalten:

myLabel = [[self copyLabelFrom:myOtherLabel] retain];
ssj
quelle
14
Dies beantwortet die Frage nicht.
Bluefloyd8
1
Was ist, wenn Ihr Etikett andere benutzerdefinierte Parameter wie numberOfLines oder tag enthält? Werden Sie alle Eigenschaften festlegen?
Iamirzhan