Create a copy of a UIView in Swift
Because objects are reference types, not value types, if you set a UIView
equal to another UIView
, the views are the same object. If you modify one you'll modifying the other as well.
I have an interesting situation where I would like to add a UIView
as a subview in another view, then I make some modifications, and those modifications should not affect the original UIView
. How can I make a copy of the UIView
so I can ensure I add that copy as a subview instead of a reference to the original UIView
?
Note that I can't recreate the view in the same way the original was created, I need some way to create a copy given any UIView
object.
You can make an UIView extension. In example snippet below, function copyView returns an AnyObject so you could copy any subclass of an UIView, ie UIImageView. If you want to copy only UIView 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: UIView = sourceView.copyView()
You can't arbitrarily copy an object. Only objects that implement the NSCopying
protocol can be copied.
However, there is a workaround: Since UIView
s can be serialized to disk (e.g. to load from a XIB), you could use NSKeyedArchiver
and NSKeyedUnarchiver
to create a serialized NSData
describing your view, then de-serialize that again to get an independent but identical object.
Update for iOS >= 12.0
Methods archivedData(withRootObject:)
and unarchivedObject(with:)
are deprecated as of iOS 12.0.
Here is an update to @Ivan Porcolab's answer using the newer API (since 11.0), also made more general to support other types.
extension NSObject {
func copyObject<T:NSObject>() throws -> T? {
let data = try NSKeyedArchiver.archivedData(withRootObject:self, requiringSecureCoding:false)
return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
}
}