2010-12-13 52 views
71

utilisant simplement cette façonEst-ce que UIView peut être copié?

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

Cela entraînera simulateur ne peut pas lancer cette application.

Essayez de retenir,

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

Toute modification de View2 s'appliquera à View1, je comprends que la part de la vue2 même mémoire avec View1.

Pourquoi ne peut-on pas copier UIView? Quelle est la raison?

Répondre

31

Votre application se bloque sans doute avec quelque chose comme:

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

La raison est que UIView ne met pas en œuvre le protocole de copie, et donc il n'y a pas de sélecteur copyWithZone en UIView.

+9

Que dois-je faire pour mettre en œuvre la copie de UIView? – Satyam

+1

Donc si vous avez une certaine combinaison de UIView et que vous voulez l'utiliser plusieurs fois, vous devrez sous-classer UIView? –

+0

Oui, sous-classe ou catégorie avec des méthodes d'usine de niveau classe qui renvoient des instances préconfigurées de cette vue. –

-5

Vous pouvez faire quelque chose comme ceci méthode:

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

} 

vous pouvez définir votre Ivar à la valeur de retour et de le conserver comme ceci:

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

cela ne répond pas à la question. – bluefloyd8

+0

que se passe-t-il si votre étiquette a d'autres paramètres personnalisés comme numberOfLines ou tag? Voulez-vous définir toutes les propriétés? – iamirzhan

150

cela pourrait fonctionner pour vous ... archivez la vue, puis désarchivez-la juste après. Cela devrait vous donner une copie profonde d'une vue:

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

Cela ressemble à un peu un hack mais fonctionne comme un rêve.La réponse de ssj ci-dessous est fondamentalement un «constructeur de copie» qui convient aux petites classes. Vous pouvez peut-être utiliser le runtime obj-c pour copier toutes les propriétés à la fois .. C'est encore plus facile;) – Patrick

+0

Cela semble trop beau pour être vrai. Dans mon cas, il lance une exception NSInvalidArgumentException ('NSConcreteAttributedString initWithString :: nil value') pour un UILabel dans l'arborescence de sous-vue. –

+1

Cela fonctionne, mais semble être très lent pour les arbres de vue même trivial. –

19

Vous pouvez créer une extension UIView. Dans l'exemple swift snippet ci-dessous, la fonction copyView renvoie un objet AnyObject de sorte que vous pouvez copier n'importe quelle sous-classe d'un UIView, ie UIImageView. Si vous souhaitez copier uniquement UIViews vous pouvez modifier le type de retour à UIView.

//MARK: - UIView Extensions 

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

Exemple d'utilisation:

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

Merci, ça marche super! AUSSI notez svp que la vue copiée n'a aucun superview (parent), aucune contrainte et aucun reconnaisseur de geste (si le parent avait n'importe). – Sajjon

+0

Copier mais avec des erreurs, certaines sous-vues ne sont pas affichées – jose920405

0

UIView ne met pas en œuvre le protocole NSCoping, voir la déclaration UIView.h:

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

Donc, si nous voulons pour avoir une méthode copy, nous devons mettre en œuvre le NSCoping protocole dans une catégorie ou plus.

4

pour swift3.0.1:

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