Can UIView be copied?

48,196

Solution 1

Your app probably crashes with something like:

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

The reason is that UIView does not implement the copying protocol, and therefore there is no copyWithZone selector in UIView.

Solution 2

this might work for you ... archive the view and then unarchive it right after. This should give you a deep copy of a view:

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

Solution 3

You can make an UIView extension. In example swift snippet below, function copyView returns an AnyObject so you could copy any subclass of an UIView, ie UIImageView. If you want to copy only UIViews you can change the return type to UIView.

//MARK: - UIView Extensions

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

Example usage:

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

Solution 4

for swift3.0.1:

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

Solution 5

UIView doesn't implement the NSCoping protocol, see the declaration in UIView.h:

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

So, if we want to have a copy like method, we need to implement the NSCoping protocol in a category or so.

Share:
48,196

Related videos on Youtube

Forrest
Author by

Forrest

iOS developer with 10+ years software building experience Shanghai,China Skype: forrest.shi.ef Recent App: PushUp! https://itunes.apple.com/us/app/pushup!/id750845921?mt=8

Updated on August 09, 2020

Comments

  • Forrest
    Forrest over 3 years

    Simply using this way:

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

    This will cause simulator can not launch this app.

    Try retain,

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

    Any modifications to view2 will apply to view1, I understand that view2 share same memory with view1.

    Why can't UIView be copied? What is the reason?

  • Satyam
    Satyam almost 12 years
    What should I do to implement the copy of UIView?
  • Anonymous White
    Anonymous White over 11 years
    So if you have a certain combination of UIView and want to use that several time you will need to subclass such UIView?
  • Engin Kurutepe
    Engin Kurutepe over 11 years
    Yes, subclassing or category with class-level factory methods that return preconfigured instances of that view.
  • Patrick Borkowicz
    Patrick Borkowicz over 11 years
    That seems like a bit of a hack but works like a dream. ssj's answer below is basically a 'copy constructor' which is fine for small classes. You can maybe use the obj-c runtime to copy all the properties at once.. This is still easier ;)
  • bluefloyd8
    bluefloyd8 about 11 years
    this isn't answering the question.
  • Ortwin Gentz
    Ortwin Gentz over 10 years
    This sounds to good to be true. In my case it throws an NSInvalidArgumentException (NSConcreteAttributedString initWithString:: nil value) for a UILabel in the subview tree.
  • Ian Newson
    Ian Newson about 10 years
    This works, but seems to be very slow for even trivial view trees.
  • nalexn
    nalexn over 9 years
    It works, but beware! It does not set values for @IBOutlets, all of them are nil after "copying"
  • Iulian Onofrei
    Iulian Onofrei almost 9 years
    This seems to ignore UIImageViews :(
  • Sajjon
    Sajjon about 8 years
    Thanks, works great! ALSO please note that the copied view has no superview (parent), no constraints and no gesture recognizers (if the parent had any).
  • Sajjon
    Sajjon about 8 years
    Thanks, works great! ALSO please note that the copied view has no superview (parent), no constraints and no gesture recognizers (if the parent had any).
  • Nick Entin
    Nick Entin almost 7 years
    agree with @IanNewson, just tried 2 approaches. A method, which: 1. instantiates new view and configure it 2. instantiates new view, configures it and archive. If archivation happened already, just call unarchiveObjectsWithData on saved data. 1. result of instantiation of 200 views, where this one is a subview ~ 0.5 sec. 2. result of instantiation of 200 views, where this one is a subview ~ 0.8 sec. The view is only UIImageView with couple autoresizing masks. I would not recommend archiving/unarchiving for duplication of views...
  • iamirzhan
    iamirzhan almost 7 years
    what if your label has other custom parameters like numberOfLines or tag? Will you set all properties?
  • paulvs
    paulvs over 6 years
    This throws a value for key (UIHighlighted) is not a boolean exception when using UIImageViews. You can use let copyView = aView.snapshotView(afterScreenUpdates: true) instead.