Algunas preguntas sobre cómo UITableView reutiliza las células

Todas las preguntas a continuación se basan en el uso de este método:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("CustomUserTableViewCell", forIndexPath: indexPath) as! CustomUserTableViewCell cell.user_id = items[indexPath.row] return cell } 
  1. ¿Es válido decir que UITableView limitará el número de instancias que se crea UITableViewCell?
  2. Cuando una instancia de celda se "reutiliza", ¿todas las variables de instancia se restablecen automáticamente? Si no, ¿debo escribir un método, resetCell() , que restablece las variables de instancia y luego lo willDisplayCell dentro del delegado willDisplayCell ?
  3. Quiero que mi celda se actualice cada vez que reciba una publicación del centro de notifications. ¿En qué lugar de mi celda debería agregar observadores a su centro de notifications? Supongo que debería llamar a listenToNotifications() dentro de willDisplayCell .
  4. De manera similar, ¿debo eliminar todos los observadores de notificación de la celda cada vez que se llama a didEndDisplayingCell() ?
  5. Si pongo todo el código de reinicio / limpieza dentro de willDisplayCell y didEndDisplayingCell , ¿qué debo colocar dentro de cellForRowAtIndexPath ?

Escribí todo mi código asumiendo que cada celda es su propia instancia (no entendía el concepto de "reutilizar" celdas), pero ahora sé que no puedo pensar así.

  1. La vista de tabla creará una instancia de cada tipo de celda que haya registrado. A partir de ahí, creará sin embargo muchas instancias que requiere para mostrarse completamente en la pantalla. Si la pantalla puede encajar en 10 celdas, habrá 10 celdas que serán reutilizables.
  2. La reutilización es un problema que es muy común mientras se usa table / collectionViews. Table / CollectionViewCells tiene un método llamado prepareForReuse que está específicamente diseñado para lo que estás indicando. Una forma de ayudar a prevenir problemas de reutilización es hacer que el controller propietario sea el que administre sus datos. Cada vez que se llama a cellForRowAtIndexPath , debe pasar el object del model apropiado, que luego tomará y configurará.

     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("CustomUserTableViewCell", forIndexPath: indexPath) as! CustomUserTableViewCell cell.configureWithObject(items[indexPath.row]) return cell } class CustomUserTableViewCell: UITableViewCell { override func prepareForReuse() { // set appropriate properties to nil that would incorrectly affect future cells } func configureWithObject(object: CustomModelObject) { // configure self with the passed in object } } 
  3. Lo más probable es que no desee que sus células observen una notificación. Eso puede generar problemas de reutilización muy complicados. La mejor ruta a realizar sería hacer que la class de controller recoja la notificación y recargue una celda específica en la ruta del índice. (Si quieres que te explique esto, puedo hacerlo)

  4. Recomendaría no hacerlo como dije en el número 3, pero si lo hace, deinit dentro del deinit de la celda. Realice una llamada como NSNotificationCenter.DefaultCenter().removeObserver(self)
  5. Deberías poner código de reinicio / limpieza en cualquier lugar. La celda para la fila será el lugar donde pasará el object model a la celda. El object del model básicamente contendrá los datos que deben mostrarse en la pantalla. Nada complejo que necesita más procesamiento (networkinges, análisis, búsqueda de bases de datos, etc.). Una vez que la célula recibe el object, debería ser cuestión de establecer properties basadas en la vista con los datos ingresados.

Aquí hay un ejemplo de flujo de datos:

Ver model : contiene lógica para llamadas de networking y recuperación de objects desde la database. Si no tiene una database, esto podría usarse para configurar cualquier representación que utilizará como fuente de datos.

Controlador de vista : se asienta en la vista de la tabla, que gestiona automáticamente la reutilización de todas las celdas que ha registrado. Te conforms con UITableViewDataSource, que es lo que te da la oportunidad de configurar las celdas. En cellForRowAtIndexPath , deberías estar en una position en la que puedes pasar la celda a un object model.

Es común ver llamadas como esta:

 let object = dataSource.objectForIndexPath(indexPath) cell.configureWithObject(object) 

Celda : toma un object model y se configura con esos datos. Un object de model básico contendría una propiedad de cadena llamada título con el valor "¡Mi impresionante título!". Cuando su celda obtenga el object, todo lo que tendrá que hacer es titleLabel.text = modelObject.title . Está bien hacer un cálculo básico adicional dentro de las celdas, pero la mayoría debe manejarse de antemano. Es un principio básico para los patrones de layout de iOS: MVC, MVVM, etc. Las tags generalmente no tienen demasiados problemas de reutilización, especialmente si organiza cosas como esta, pero las imágenes, por otro lado, sí lo hacen. En prepareForReuse es común tener una llamada como myImageView.image = nil . Eso asegurará que esté listo para la próxima vez que se configure la celda.

  1. sí, se administrará el número de instancias para usted.

  2. No, no se restablecen automáticamente. Puede anular prepareForReuse en su subclass UITableViewCell o puede manejar todos los casos en cellForRowAtIndexPath .

  3. Suponiendo que desea que todas sus celdas escuchen las mismas notifications, puede registrar las notifications en awakeFromNib si ha utilizado storyboards o un xib o puede registrarse en el init de su subclass UITableViewCell. De lo contrario, puede hacerlo cellForRowAtIndexPath

  4. Debe eliminar la observación en deinit . También debe eliminar la observación en prepareForReuse , si las células necesitan escuchar diferentes notifications.

  5. willDisplayCell se usa generalmente para vistas de tabla estáticas. Debe configurar su celda en cellForRowAtIndexPath