ios - Crie uma cópia de um UIView no Swift




(6)

Além disso, você pode usar esse padrão para copiar a visualização do controlador de exibição

let vc = UIViewController() 
let anotherVc = UIViewController()
vc.view = anotherVc.copyView()

Você pode precisar disso para armazenar em cache o controlador de exibição ou a clonagem.

Como os objetos são tipos de referência, não tipos de valor, se você definir um UIView igual a outro UIView , as visualizações serão o mesmo objeto. Se você modificar um, também modificará o outro.

Eu tenho uma situação interessante em que gostaria de adicionar um UIView como uma subvisão em outro modo de exibição. Depois, faço algumas modificações e essas modificações não devem afetar o UIView original. Como posso fazer uma cópia do UIView para garantir que eu adicione essa cópia como uma subvisão em vez de uma referência ao UIView original?

Observe que não consigo recriar a exibição da mesma maneira que o original foi criado; preciso criar uma cópia para qualquer objeto UIView .


Esta resposta mostra como fazer o que @uliwitness sugeriu. Ou seja, obtenha um objeto idêntico arquivando-o e depois desarquivando-o. (Também é basicamente o que Ivan Porkolab fez em sua resposta, mas em um formato mais legível, eu acho.)

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

Notas

  • Desarquivar os dados cria um objeto do tipo AnyObject . Nós usamos as! UIView as! UIView para digitar lança de volta para um UIView pois sabemos que é isso que é. Se nossa view fosse um UITextView , poderíamos digitar cast it as! UITextView as! UITextView .
  • O myViewCopy não tem mais uma visualização pai.
  • Algumas pessoas mencionam alguns problemas ao trabalhar com o UIImage . No entanto, veja this e this resposta.

Atualizado para o Swift 3.0


Uma solução adicional pode ser criar apenas um novo UIView e copiar sobre quaisquer propriedades críticas. Isso pode não funcionar no caso do OP, mas pode funcionar muito bem para outros casos.

Por exemplo, com um UITextView , provavelmente tudo que você precisa é o quadro e o texto atribuído:

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

Você deve usar o padrão Prototype

Exemplo do protótipo:

class ThieveryCorporationPersonDisplay {
    var name: String?
    let font: String

    init(font: String) {
        self.font = font
    }

    func clone() -> ThieveryCorporationPersonDisplay {
        return ThieveryCorporationPersonDisplay(font:self.font)
    }
}

Um exemplo de uso de protótipo:

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"

Você pode fazer uma extensão UIView. No exemplo de trecho abaixo, a função copyView retorna um AnyObject para que você possa copiar qualquer subclasse de um UIView, ou seja , UIImageView. Se você deseja copiar apenas o UIView, você pode alterar o tipo de retorno para UIView.

//MARK: - UIView Extensions

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

Exemplo de uso:

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

Atualização para iOS 12.0

Os métodos archivedData(withRootObject:) e unarchivedObject(with:) estão obsoletos no iOS 12.0.

Aqui está uma atualização da resposta de @Ivan Porcolab usando a API mais recente (desde 11.0), também mais genérica para oferecer suporte a outros tipos.

extension NSObject {
    func copyObject<T:NSObject>() throws -> T? {
        let data = try NSKeyedArchiver.archivedData(withRootObject:self, requiringSecureCoding:false)
        return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
    }
}




uiview