Создайте копию UIView в Swift
Поскольку объекты являются ссылочными типами, а не типами значений, если вы устанавливаете UIView
равным другому UIView
, представления представляют собой один и тот же объект. Если вы измените его, вы также измените другое.
У меня есть интересная ситуация, когда я хотел бы добавить UIView
в качестве подсмотра в другом представлении, затем я вношу некоторые изменения, и эти модификации не должны влиять на исходный UIView
. Как сделать копию UIView
, чтобы я мог добавить эту копию в качестве подвью, а не ссылку на исходный UIView
?
Обратите внимание, что я не могу воссоздать представление так же, как было создано оригинал, мне нужно каким-то образом создать копию с любым объектом UIView
.
Ответы
Ответ 1
Вы не можете произвольно копировать объект. Можно копировать только объекты, реализующие протокол NSCopying
.
Однако существует временное решение: поскольку UIView
может быть сериализовано на диск (например, для загрузки из XIB), вы можете использовать NSKeyedArchiver
и NSKeyedUnarchiver
для создания сериализованного NSData
, описывающего ваше представление, затем de-serialize, чтобы снова получить независимый, но идентичный объект.
Ответ 2
Вы можете сделать расширение 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
}
}
Пример использования:
let sourceView = UIView()
let copiedView: UIView = sourceView.copyView()
Ответ 3
Я думаю, что вы должны связать UIView с .nib и просто создать новый.
Собственность не будет одинаковой, но вы сохраните внешний вид и методы.
Ответ 4
Этот ответ показывает, как сделать то, что предложил @uliwitness. То есть, получить идентичный объект, архивируя его, а затем его разблокировать. (Это также в основном то, что Иван Порколаб сделал в своем ответе, но в более читаемом формате, я думаю.)
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
Примечания
- Уничтожение данных создает объект типа
AnyObject
. Мы использовали as! UIView
, чтобы напечатать его обратно в UIView
, так как мы знаем, что это такое. Если наш взгляд был UITextView
, тогда мы могли бы набрать его as! UITextView
.
-
myViewCopy
больше не имеет родительского представления.
- Некоторые люди упоминают некоторые проблемы при работе с
UIImage
. Однако см. этот и этот ответ.
Обновлен до Swift 3.0
Ответ 5
Вы должны использовать шаблон Prototype
Пример прототипа:
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"
Ответ 6
Дополнительным решением может быть просто создание нового UIView
, а затем копирование любых критических свойств. Это может не работать в случае OP, но оно может очень хорошо работать для других случаев.
Например, при UITextView
, возможно, вам понадобится только фрейм и атрибут текста:
let textViewCopy = UITextView(frame: textView.frame)
textViewCopy.attributedText = textView.attributedText