在Swift中创建UIView的副本

Jor*_*n H 43 uiview ios swift

因为对象是引用类型而不是值类型,所以如果设置UIView等于另一个UIView,则视图是同一个对象.如果你修改一个,你也会修改另一个.

我有一个有趣的情况,我想UIView在另一个视图中添加一个子视图,然后我做一些修改,这些修改不应该影响原始UIView.我如何制作副本,UIView以便我可以确保将该副本添加为子视图而不是对原始副本的引用UIView

请注意,我无法以创建原始的方式重新创建视图,我需要一些方法来创建给定任何UIView对象的副本.

Iva*_*lab 116

你可以制作一个UIView扩展.在下面的示例代码段中,函数copyView返回AnyObject,因此您可以复制UIView的任何子类, UIImageView.如果你想复制的UIView你可以改变返回类型的UIView.

//MARK: - UIView Extensions

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

用法示例:

let sourceView = UIView()
let copiedView: UIView = sourceView.copyView()
Run Code Online (Sandbox Code Playgroud)

  • 自 iOS 12.0 起,方法 `archivedData(withRootObject:)` 和 `unarchivedObject(with:)` 已被*弃用*。 (6认同)
  • 但它似乎失去了IBOutlet绑定 (5认同)
  • 这怎么不是 UIView 上的工厂方法? (2认同)

uli*_*ess 19

你不能随意复制一个对象.只能NSCopying复制实现协议的对象.

但是,有一个解决方法:由于UIViews可以序列化为磁盘(例如,从XIB加载),您可以使用NSKeyedArchiverNSKeyedUnarchiver创建NSData描述视图的序列化,然后再次反序列化以获得独立但相同的对象.


Dav*_*mes 6

iOS 12.0更新

自iOS 12.0起不推荐使用方法archivedData(withRootObject:)unarchivedObject(with:)

这是使用较新的API(自11.0起)对@Ivan Porcolab的答案的更新,它也变得更加通用以支持其他类型。

extension NSObject {
    func copyObject<T:NSObject>() throws -> T? {
        let data = try NSKeyedArchiver.archivedData(withRootObject:self, requiringSecureCoding:false)
        return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
    }
}
Run Code Online (Sandbox Code Playgroud)


Sur*_*gch 5

这个答案显示了如何做@uliwitness 的建议。也就是说,通过存档然后取消存档来获得相同的对象。(这基本上也是 Ivan Porkolab 在他的回答中所做的,但我认为是一种更易读的格式。)

let myView = UIView()

// create an NSData object from myView
let archive = NSKeyedArchiver.archivedData(withRootObject: myView)

// create a clone by unarchiving the NSData
let myViewCopy = NSKeyedUnarchiver.unarchiveObject(with: archive) as! UIView
Run Code Online (Sandbox Code Playgroud)

笔记

  • 取消归档数据会创建一个类型为 的对象AnyObject。我们过去常常as! UIView将其强制转换为 a,UIView因为我们知道它就是这样。如果我们的视图是 aUITextView那么我们可以输入 cast it as! UITextView
  • myViewCopy不再有父视图。
  • 有些人在使用UIImage. 但是,请参阅答案。

更新到 Swift 3.0