Подтвердить что ты не робот

Создайте копию UIView в Swift

Поскольку объекты являются ссылочными типами, а не типами значений, если вы устанавливаете UIView равным другому UIView, представления представляют собой один и тот же объект. Если вы измените его, вы также измените другое.

У меня есть интересная ситуация, когда я хотел бы добавить UIView в качестве подсмотра в другом представлении, затем я вношу некоторые изменения, и эти модификации не должны влиять на исходный UIView. Как сделать копию UIView, чтобы я мог добавить эту копию в качестве подвью, а не ссылку на исходный UIView?

Обратите внимание, что я не могу воссоздать представление так же, как было создано оригинал, мне нужно каким-то образом создать копию с любым объектом UIView.

4b9b3361

Ответ 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