2014-09-11 15 views
18

我試圖讓我的視圖控制器保持乾淨,如本文所述objc.io Issue #1 Lighter View Controllers。我在Objective-C中測試了這個方法,它工作正常。我有一個單獨的類實現UITableViewDataSource方法。將數據源分離到Swift中的另一個類

#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 

從實現代碼如下控制器,所有我需要做的就是實例化這個類的一個實例,並將其設置爲tableview中的數據源和它完美的作品。

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

現在我試圖在Swift中做同樣的事情。首先這是我的代碼。它幾乎是上面的Objective-C代碼的翻譯。

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 
    } 

} 

我這樣稱呼它。

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

但該應用程序崩潰,出現以下錯誤。

- [NSConcreteNotification的tableView:numberOfRowsInSection:]:無法識別的選擇發送到實例

我檢查的TableDataSourceinit方法和項目和小區標識符被傳遞細。我不得不聲明UITableViewDataSource方法public並刪除override關鍵字,否則會導致編譯時錯誤。

我對這裏出了什麼問題毫無頭緒。任何人都可以請幫我嗎?

謝謝。

+0

可以在崩潰時顯示堆棧跟蹤嗎? – 2014-09-11 13:56:02

+2

看起來您的數據源未被保留。你在哪裏存儲參考? – jlehr 2014-09-11 14:39:13

+3

@jlehr這確實是問題所在。我不想保存它!我做了一個屬性'var dataSource:TableDataSource!'並將其分配給tableview的'dataSource'屬性,它現在可以工作:)謝謝。 – Isuru 2014-09-11 16:20:08

回答

25

爲數據源創建一個屬性並將其與您的tableview一起使用。

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 

    } 
} 
+2

可以在這裏粘貼TableDataSource類嗎? – 2015-12-18 13:38:49

4

我用下面的代碼,更通用的方法,作爲一個嘗試..

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] 
    } 

} 

在視圖控制器

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. 
} 

用這種方法在我的小項目WorldCountriesSwift

+0

我將DataSource放置爲單獨文件,但不知道如何「偵聽單擊事件並將點擊的項目發送到DetailViewController」。 '''類PicturesDataSource:NSObject的,UITableViewDataSource { }''' 內部PicturesDataSource 「故事板」 和 「navigationController」 不可&因此'''如果讓detailViewController = storyboard.instantiateViewController(withIdentifier: 「PictureDetailView」 )爲? PictureDetailViewController&navigationController?.pushViewController(detailViewController,animated:true)'''不工作。 – 2017-09-10 12:16:48

+0

嘗試在viewcontroller的didselectrow方法中添加dataSource?.item(at:indexPath),然後嘗試呈現詳細信息pictureVC.present(PictureDetailViewController .....) – anoop4real 2017-09-10 15:37:30

0

通過「ayalcinkaya」擴展了接受的答案,解釋了如何但不是爲什麼

最有可能發生的事情是,你TableDataSource被釋放爲tableview.dataSource is a weak reference,這就是爲什麼建立一個屬性解決了這個問題,因爲它創建了一個有力的參考,避免了數據源代表被釋放。

相關問題