Czy można skopiować UIView?


81

Po prostu używając w ten sposób:

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

Spowoduje to, że symulator nie będzie mógł uruchomić tej aplikacji.

Spróbuj zachować,

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

Wszelkie modyfikacje view2będą miały zastosowanie do view1, rozumiem, że view2mają tę samą pamięć z view1.

Dlaczego nie można UIViewgo skopiować? Jaki jest powód?

Odpowiedzi:


33

Twoja aplikacja prawdopodobnie ulega awarii i wyświetla się na przykład:

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

Powodem jest to, że UIView nie implementuje protokołu kopiowania i dlatego copyWithZonew UIView nie ma selektora.


10
Co powinienem zrobić, aby zaimplementować kopię UIView?
Satyam

1
Więc jeśli masz określoną kombinację UIView i chcesz jej użyć kilka razy, będziesz musiał podklasować taką UIView?
Anonymous White

Tak, tworzenie podklas lub kategorii z metodami fabrycznymi na poziomie klasy, które zwracają wstępnie skonfigurowane wystąpienia tego widoku.
Engin Kurutepe

162

to może zadziałać ... zarchiwizuj widok, a następnie rozpakuj go. To powinno dać ci dokładną kopię widoku:

id copyOfView = 
[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalView]];

1
Wydaje się, że to trochę hack, ale działa jak sen. Odpowiedź ssj poniżej to w zasadzie „konstruktor kopiujący”, który jest odpowiedni dla małych klas. Możesz użyć środowiska uruchomieniowego obj-c, aby skopiować wszystkie właściwości naraz .. To jest nadal łatwiejsze;)
Patrick Borkowicz

1
To działa, ale wydaje się być bardzo powolne nawet dla drzew o trywialnych widokach.
Ian Newson

6
Działa, ale uważaj! Nie ustawia wartości dla @IBOutlets, wszystkie z nich są zerowe po "skopiowaniu"
nalexn

1
To zdaje się ignorować UIImageViews :(
Iulian Onofrei

1
Dzięki, działa świetnie! RÓWNIEŻ proszę zauważyć, że skopiowany widok nie ma superviewu (rodzica), żadnych ograniczeń ani żadnych rozpoznawania gestów (jeśli rodzic je miał).
Sajjon

25

Możesz zrobić rozszerzenie UIView. W poniższym przykładzie swift snippet funkcja copyView zwraca AnyObject, dzięki czemu można skopiować dowolną podklasę UIView, tj . UIImageView. Jeśli chcesz skopiować tylko UIViews, możesz zmienić typ zwrotu na UIView.

//MARK: - UIView Extensions

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

Przykładowe użycie:

let sourceView = UIView()
let copiedView = sourceView.copyView()

1
Dzięki, działa świetnie! RÓWNIEŻ proszę zauważyć, że skopiowany widok nie ma superviewu (rodzica), żadnych ograniczeń ani żadnych rozpoznawania gestów (jeśli rodzic je miał).
Sajjon

6

dla swift3.0.1:

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

1

UIViewnie implementuje NSCopingprotokołu, zobacz deklarację w UIView.h :

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

Tak więc, jeśli chcemy mieć copypodobną metodę, musimy zaimplementować NSCopingprotokół w jakiejś kategorii.


-6

Możesz zrobić taką metodę jak ta:

-(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];

}

Następnie możesz ustawić swój ivar na wartość zwracaną i zachować ją w ten sposób:

myLabel = [[self copyLabelFrom:myOtherLabel] retain];

14
to nie jest odpowiedzią na pytanie.
bluefloyd8

1
co, jeśli Twoja etykieta ma inne parametry niestandardowe, takie jak numberOfLines lub tag? Czy ustawisz wszystkie właściwości?
iamirzhan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.