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?

Forrest
źródło

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.

Engin Kurutepe
źródło
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]];
j2emanue
źródło
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()
Ivan Porkolab
źródło
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
 }
}
Sour LeangChhean
źródło
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.

HongchaoZhang
źródło
-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];
ssj
źródło
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