Cómo utilizar las extensiones de protocolo para enlazar clases de modelo con interfaces?

Algunas veces tu tienes que bind los mismos tipos de objetos en múltiples vistas, como en un UIViewController, UITableViewcell, o en un UICollectionViewCell. Muy a menudo, el binding del código es similar en todas las vistas, entonces sería una grandiosa idea si se puede reusar. Usaremos un protocolo de Swift y extensiones para hacerlo.

Supongamos que tenemos una Struct user.

struct User {
    var name: String!
    var email: String!
    var bio: String!
    var image: UIImage? = nil
    
    init(name: String, email: String, bio: String) {
        self.name = name
        self.email = email
        self.bio = bio
    }
}

Ya que contamos con nuestro modelo user, simplemente tenemos que crear un protocolo que se puede traducir como una interfaz en java para poder crear nuestro Bindiable.

protocol UserBindable: AnyObject {
    var user: User? { get set }
    
    var nameLabel: UILabel! { get }
    var emailLabel: UILabel! { get }
    var bioLabel: UILabel! { get }
    var imageView: UIImageView! { get }
}

La primer variable user es usada para el bind, y todos las otras son subclases de UIView que nosotros podemos usar para el bind del usuario.

Ahora debemos crear una extensión del protocolo.

extension UserBindable {
    
    // Make the views optionals
        
    var nameLabel: UILabel! {
        return nil
    }
    
    var emailLabel: UILabel! {
        return nil
    }
    
    var bioLabel: UILabel! {
        return nil
    }
    
    var imageView: UIImageView! {
        return nil
    }
    
    // Bind
    
    func bind(user: User) {
        self.user = user
        bind()
    }
    
    func bind() {
        
        guard let user = self.user else {
            return
        }
    
        if let nameLabel = self.nameLabel {
            nameLabel.text = user.name
        }
        
        if let bioLabel = self.bioLabel {
            bioLabel.text = user.bio
        }
        
        if let emailLabel = self.emailLabel {
            emailLabel.text = user.email
        }
        
        if let imageView = self.imageView {
            imageView.image = user.image
        }
    }
}

Aquí, nosotros separamos la extensión en dos secciones:

  • La primera es usada para proveer un valor default (nil) para cada una de las vistas, entonces los objetos que implementaremos del protocolo no tendrán que existir. Para la instancia de esta, algunas de nuestras vistas puede que excluyan image, pero otras sí puede que lo utilicen.
  • Nosotros tomamos los valores de las propiedades del usuario y las establecemos en las views.

Ahora, casi todo el trabajo está terminado. Si nosotros presentamos una lista de usuarios, nosotros tendremos que crear UITableViewCell. Supongamos que la celda necesita mostrar nada más el nombre y el email.

class UserTableViewCell: UITableViewCell, UserBindable {

    var user: User?
    
    // we can set the labels in interface builder or with by code. 
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
}

Eso es todo. Nuestra celda implementaUserBindable, entonces sabemos como el bind es la interfaz a un usuario. En nuestroUITableViewDataSource  podemos hacer:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UserTableViewCell
        let user = // find the user from your array or whatever
        cell.bind(user)
        return cell
    }

Si nosotros quisiéramos mostrar mas detalles después de seleccionar un usuario, tenemos un view controller como este:

class UserDetailViewController: UIViewController, UserBindable {
    
    var user: User?
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
    @IBOutlet weak var bioLabel: UILabel!
    @IBOutlet weak var imageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
	 // here we suppose that we have set the user value before the viewDidLoad
        bind()
    }
}

Como se puede ver, todos los elementos de nuestro código binding están siendo re-usados en esta vista.

Conclusión:

El binding que realizamos es realmente útil ya que puedes implementarlo en muchas vistas con muy poco codigo, lo cual tu codigo quedaria mas limpio, mantenible y fácil .

Leonardo Durazo Duran.

https://www.toptal.com/swift/tips-and-practices

0 comments on “Cómo utilizar las extensiones de protocolo para enlazar clases de modelo con interfaces?Add yours →

Leave a Reply

Your email address will not be published. Required fields are marked *