objetos herencia clases ios objective-c uitableview swift datasource

ios - clases - herencia en swift 4



Separando el origen de datos a otra clase en Swift (3)

Cree una propiedad para el origen de datos y utilícela con su vista de tabla.

class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! var dataSource:TableDataSource! override func viewDidLoad() { super.viewDidLoad() dataSource = TableDataSource(items: ["One", "Two", "Three"], cellIdentifier: "Cell") tableView.dataSource = dataSource } }

Estoy tratando de mantener mis controladores de vista limpios como se describe en este artículo objc.io Problema # 1 Controladores de vista más claros . Probé este método en Objective-C y funciona bien. Tengo una clase separada que implementa métodos UITableViewDataSource .

#import "TableDataSource.h" @interface TableDataSource() @property (nonatomic, strong) NSArray *items; @property (nonatomic, strong) NSString *cellIdentifier; @end @implementation TableDataSource - (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier { self = [super init]; if (self) { self.items = items; self.cellIdentifier = cellIdentifier; } return self; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.items.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath]; cell.textLabel.text = self.items[indexPath.row]; return cell; } @end

Desde el controlador de Tableview, todo lo que tengo que hacer es crear una instancia de esta clase y establecerla como la fuente de datos de la vista de tabla y funciona perfectamente.

self.dataSource = [[TableDataSource alloc] initWithItems:@[@"One", @"Two", @"Three"] cellIdentifier:@"Cell"]; self.tableView.dataSource = self.dataSource;

Ahora estoy tratando de hacer lo mismo en Swift. Primero aquí está mi código. Es casi una traducción del código Objective-C de arriba.

import Foundation import UIKit public class TableDataSource: NSObject, UITableViewDataSource { var items: [AnyObject] var cellIdentifier: String init(items: [AnyObject]!, cellIdentifier: String!) { self.items = items self.cellIdentifier = cellIdentifier super.init() } public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell cell.textLabel?.text = items[indexPath.row] as? String return cell } }

Y lo llamo así.

let dataSource = TableDataSource(items: ["One", "Two", "Three"], cellIdentifier: "Cell") tableView.dataSource = dataSource

Pero la aplicación se bloquea con el siguiente error.

- [NSConcreteNotification tableView: numberOfRowsInSection:]: selector no reconocido enviado a la instancia

TableDataSource método de TableDataSource de TableDataSource y los elementos y el identificador de celda se pasa bien. Tuve que declarar UITableViewDataSource métodos de UITableViewDataSource y eliminar la palabra clave de override contrario daría errores de compilación.

No tengo ni idea de lo que está mal aquí. ¿Por favor, puede alguien ayudarme?

Gracias.


Extendiendo la respuesta aceptada por "ayalcinkaya", que explica el cómo pero no el por qué :

Lo más probable es que lo que está sucediendo es que su TableDataSource está siendo desasignado como tableview.dataSource es una referencia débil , es por eso que crear una propiedad resuelve el problema, ya que crea una referencia fuerte y evita que el delegado dataSource se desasigne.


Utilicé el siguiente código, para un enfoque más genérico, como un intento ...

import UIKit class CustomDataSource<ItemsType, CellType:UITableViewCell>: NSObject, UITableViewDataSource { typealias ConfigureCellClosure = (_ item: ItemsType, _ cell: CellType) -> Void private var items: [ItemsType] private let identifier: String private var configureCellClosure: ConfigureCellClosure init(withData items: [ItemsType], andId identifier: String, withConfigBlock config:@escaping ConfigureCellClosure) { self.identifier = identifier self.items = items self.configureCellClosure = config } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: self.identifier, for: indexPath) as! CellType configureCellClosure(items[indexPath.row], cell) return cell } func item(at indexpath: IndexPath) -> ItemsType { return items[indexpath.row] } }

En vista controlador

var dataSource: CustomDataSource<CellObject, CustomTableViewCell>? override func viewDidLoad() { super.viewDidLoad() dataSource = CustomDataSource<CellObject, CustomTableViewCell>(withData: customDataStore.customData(), andId: CustomTableViewCell.defaultReuseIdentifier) { (cellObject, cell) in cell.configureCell(with: cellObject) } customTableView.dataSource = dataSource // Do any additional setup after loading the view. }

Usé este enfoque en mi pequeño proyecto WorldCountriesSwift