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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:47:45  来源:igfitidea点击:

Create a copy of a UIView in Swift

iosswiftuiview

提问by Jordan H

Because objects are reference types, not value types, if you set a UIViewequal 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 UIViewas 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 UIViewso 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 UIViewobject.

请注意,我无法以与创建原始视图相同的方式重新创建视图,我需要某种方式来创建给定任何UIView对象的副本。

采纳答案by uliwitness

You can't arbitrarily copy an object. Only objects that implement the NSCopyingprotocol can be copied.

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

However, there is a workaround: Since UIViews can be serialized to disk (e.g. to load from a XIB), you could use NSKeyedArchiverand NSKeyedUnarchiverto create a serialized NSDatadescribing your view, then de-serialize that again to get an independent but identical object.

但是,有一个解决方法:由于UIViews 可以序列化到磁盘(例如从 XIB 加载),您可以使用NSKeyedArchiverNSKeyedUnarchiver创建一个序列化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 used as! UIViewto type cast it back to a UIViewsince we know that's what it is. If our view were a UITextViewthen we could type cast it as! UITextView.
  • The myViewCopyno longer has a parent view.
  • Some peoplemention some problems when working with UIImage. However, see thisand thisanswer.
  • 取消归档数据会创建一个类型为 的对象AnyObject。我们过去常常as! UIView将其强制转换为 a,UIView因为我们知道它就是这样。如果我们的视图是 aUITextView那么我们可以输入 cast it as! 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 UIViewand 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.

您可能需要它来缓存视图控制器或克隆。