在Swift中创build一个UIView的副本

由于对象是引用types,而不是值types,所以如果将UIView设置为与另一个UIView相同,则视图是相同的对象。 如果你修改一个,你也会修改其他的。

我有一个有趣的情况,我想添加一个UIView作为子视图在另一个视图,然后我做了一些修改,这些修改不应该影响原来的UIView 。 我怎样才能做一个UIView的副本,所以我可以确保我添加副本作为一个子视图,而不是对原始UIView的引用?

请注意,我不能以创build原始相同的方式重新创build视图,我需要一些方法来创build任何UIView对象的副本。

您不能任意复制对象。 只有实现NSCopying协议的NSCopying才能被复制。

但是,有一个解决方法:因为UIView可以被序列化到磁盘(例如从XIB加载),您可以使用NSKeyedArchiverNSKeyedUnarchiver创build一个序列化的NSData描述您的视图,然后反序列化,以获得独立但相同的对象。

你可以做一个UIView扩展。 在下面的示例代码片段中,函数copyView返回一个AnyObject,因此您可以复制UIView的任何子类, UIImageView。 如果只想复制UIView,则可以将返回types更改为UIView。

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

用法示例:

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

我认为你应该把你的UIView与一个.nib连接起来,然后创build一个新的。

财产将不一样,但你保持外观和方法。

这个答案显示如何做@uliwitnessbuild议。 也就是说,通过归档并取消归档来获得相同的对象。 (这也基本上是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 

笔记

  • 取消存档数据会创build一个AnyObjecttypes的对象。 我们用作as! UIView as! UIViewtypes转换回UIView因为我们知道这是什么。 如果我们的观点是一个UITextView那么我们可以将其转换as! UITextView as! UITextView
  • myViewCopy不再有父视图。
  • 有些人在使用UIImage时提到了一些问题。 但是,看到这个和这个答案。

更新到Swift 3.0

你必须使用模式原型

原型示例:

 class ThieveryCorporationPersonDisplay { var name: String? let font: String init(font: String) { self.font = font } func clone() -> ThieveryCorporationPersonDisplay { return ThieveryCorporationPersonDisplay(font:self.font) } } 

使用原型的一个例子:

 let Prototype = ThieveryCorporationPersonDisplay(font:"Ubuntu") let Philippe = Prototype.clone() Philippe.name = "Philippe" let Christoph = Prototype.clone() Christoph.name = "Christoph" let Eduardo = Prototype.clone() Eduardo.name = "Eduardo" 

一个额外的解决scheme可能是创build一个新的UIView ,然后复制任何关键的属性。 这在OP的情况下可能不起作用,但对于其他情况可能会起作用。

例如,用UITextView ,可能所有你需要的是框架和属性文本:

 let textViewCopy = UITextView(frame: textView.frame) textViewCopy.attributedText = textView.attributedText