ios 在 Swift 中创建 UIView 的副本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27121655/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create a copy of a UIView in Swift
提问by Jordan H
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.
因为对象是引用类型,而不是值类型,如果将 a 设置UIView
为 another UIView
,则视图是同一个对象。如果你修改一个,你也会修改另一个。
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
?
我有一个有趣的情况,我想UIView
在另一个视图中添加一个子视图,然后进行一些修改,这些修改不应影响原始UIView
. 如何制作 的副本,UIView
以便确保将该副本添加为子视图而不是对原始的引用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.
请注意,我无法以与创建原始视图相同的方式重新创建视图,我需要某种方式来创建给定任何UIView
对象的副本。
采纳答案by uliwitness
You can't arbitrarily copy an object. Only objects that implement the NSCopying
protocol can be copied.
你不能随意复制一个对象。只能NSCopying
复制实现协议的对象。
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.
但是,有一个解决方法:由于UIView
s 可以序列化到磁盘(例如从 XIB 加载),您可以使用NSKeyedArchiver
和NSKeyedUnarchiver
创建一个序列化NSData
描述您的视图,然后再次反序列化以获得独立但相同的对象。
回答by Ivan Porkolab
You can make an UIView extension. In example snippet below, function copyView returns an AnyObject so you could copy any subclass of an UIView, ieUIImageView. If you want to copy onlyUIView you can change the return type to UIView.
你可以做一个 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
}
}
Example usage:
用法示例:
let sourceView = UIView()
let copiedView: UIView = sourceView.copyView()
回答by David James
Update for iOS 12.0
iOS 12.0 更新
Methods archivedData(withRootObject:)
and unarchivedObject(with:)
are deprecated as of iOS 12.0.
方法archivedData(withRootObject:)
和unarchivedObject(with:)
自 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.
这是使用较新 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
}
}
回答by Florian
I think that you should link you UIView with a .nib and just create a new one.
我认为您应该将 UIView 与 .nib 链接起来,然后创建一个新的。
Property will not be the same, but you keep appearance and methods.
属性不会一样,但你保持外观和方法。
回答by Suragch
This answer shows how to do what @uliwitness suggested. That is, get an identical object by archiving it and then unarchiving it. (It is also basically what Ivan Porkolab did in his answer, but in a more readable format, I think.)
这个答案显示了如何做@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
Notes
笔记
- Unarchiving the data creates an object of type
AnyObject
. We usedas! UIView
to type cast it back to aUIView
since we know that's what it is. If our view were aUITextView
then we could type cast itas! UITextView
. - The
myViewCopy
no longer has a parent view. - Some peoplemention some problems when working with
UIImage
. However, see thisand thisanswer.
- 取消归档数据会创建一个类型为 的对象
AnyObject
。我们过去常常as! UIView
将其强制转换为 a,UIView
因为我们知道它就是这样。如果我们的视图是 aUITextView
那么我们可以输入 cast itas! UITextView
。 - 将
myViewCopy
不再有父视图。 - 有些人在使用
UIImage
. 但是,请参阅此和此答案。
Updated to Swift 3.0
更新到 Swift 3.0
回答by Beslan Tularov
You must use pattern Prototype
您必须使用模式原型
Example of the prototype:
原型示例:
class ThieveryCorporationPersonDisplay {
var name: String?
let font: String
init(font: String) {
self.font = font
}
func clone() -> ThieveryCorporationPersonDisplay {
return ThieveryCorporationPersonDisplay(font:self.font)
}
}
An example of using prototype:
使用原型的示例:
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"
回答by Suragch
An addition solution could be to just create a new UIView
and then copy over any critical properties. This may not work in the OP's case, but it could very well work for other cases.
另外的解决方案可能是创建一个新的UIView
,然后复制任何关键属性。这在 OP 的情况下可能不起作用,但在其他情况下可能会很好地工作。
For example, with a UITextView
, probably all you would need is the frame and attributed text:
例如,对于 a UITextView
,您可能只需要框架和属性文本:
let textViewCopy = UITextView(frame: textView.frame)
textViewCopy.attributedText = textView.attributedText
回答by Mohamed Deux
Additionally you can use this pattern to copy View controller view
此外,您可以使用此模式复制视图控制器视图
let vc = UIViewController()
let anotherVc = UIViewController()
vc.view = anotherVc.copyView()
You may need this for caching view controller or cloning.
您可能需要它来缓存视图控制器或克隆。