Swift 一些UITableView委托方法被调用了5次,其他方法根本没有被调用

Swift 一些UITableView委托方法被调用了5次,其他方法根本没有被调用,swift,uitableview,xcode7,Swift,Uitableview,Xcode7,我有一个独立于UIViewController的类,该类被设置为我的UITableView委托和UITableViewDataSource 我尝试初始化UITableViewDelegate类,然后将其分配给UITableView 奇怪的是 方法NumberOfSectionsTableView和tableView(:numberOfRowsInSection)被调用了五次,而tableView(uu:cellForRowAtIndexPath)从未被调用 我已经验证了NumberOfSecti

我有一个独立于UIViewController的类,该类被设置为我的UITableView委托和UITableViewDataSource

我尝试初始化UITableViewDelegate类,然后将其分配给UITableView

奇怪的是

方法NumberOfSectionsTableView和tableView(:numberOfRowsInSection)被调用了五次,而tableView(uu:cellForRowAtIndexPath)从未被调用

我已经验证了NumberOfSectionsTableView和tableView(:numberOfRowsInSection)返回的值至少有一个

如果我将UITableViewDataSource和UITableViewDelegate方法移动到ViewController,代码将正常工作。

是什么导致了这种行为

class MessagesViewController: UIViewController, ManagedObjectContextSettable {

    var managedObjectContext: NSManagedObjectContext!
    @IBOutlet var messagesTableView: UITableView!

    override func viewDidLoad() {
        setupMessagesTableView()
    }

    private func setupMessagesTableView() {
        let dataSource = MessagesTableViewDataSource(managedObjectContext: managedObjectContext, conversationList: fetchedObjects as! [Conversation])
        // Assume fetchedObjects is an array fetched from CoreData store. I have removed the code that defines it for the purpose of this example.
        self.messagesTableView.dataSource = dataSource
        self.messagesTableView.delegate = dataSource
    }

}

class MessagesTableViewDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {

    var managedObjectContext: NSManagedObjectContext!
    var conversationList: [Conversation]

    required init(managedObjectContext: NSManagedObjectContext, conversationList: [Conversation]) {
        self.managedObjectContext = managedObjectContext
        self.conversationList = conversationList
        let conversation = Conversation()
        self.conversationList.append(conversation)            
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.conversationList.count    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("CellID", forIndexPath: indexPath) as UITableViewCell!
        let conversation: Conversation = self.conversationList[indexPath.row]
        cell.textLabel!.text = conversation.name as? String
        return cell
    }

}

检查表视图的框架。如果高度或宽度为0,
tableView:cellForRowAtIndexPath:
将不会被调用。

我也有同样的问题,我认为这是UIKit中的一个错误

我创建了一个简单的列表数据源和一个小的视图控制器来测试这一点,我可以确认
cellforrowatinexpath
没有被调用numberOfRowsInSection'返回大于0的值,并且tableView的帧设置正确

同样的代码在放入视图控制器时也会起作用。也许我遗漏了一些东西,但我认为这是苹果方面的一个缺陷

SimpleListDataSource.swift

import UIKit

class SimpleListDataSource : NSObject, UITableViewDataSource {

    var items: [String]
    var cellIdentifier: String

    typealias CellConfiguration = (UITableViewCell, String) -> ()
    var cellConfiguration: CellConfiguration

    init(items: [String], cellIdentifier: String, cellConfiguration: CellConfiguration) {
        self.items = items
        self.cellIdentifier = cellIdentifier
        self.cellConfiguration = cellConfiguration
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("Number of rows: \(self.items.count)")
        return self.items.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        print(__FUNCTION__)
        let cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier, forIndexPath: indexPath)
        self.cellConfiguration(cell, self.items[indexPath.row])
        return cell
    }
}
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let data = ["a", "b", "c"]
        let dataSource = SimpleListDataSource(items: data, cellIdentifier: "cell") { (cell, string) -> () in
            cell.textLabel?.text = string
        }

        self.tableView.dataSource = dataSource
        self.tableView.reloadData()
    }
}
ViewController.swift

import UIKit

class SimpleListDataSource : NSObject, UITableViewDataSource {

    var items: [String]
    var cellIdentifier: String

    typealias CellConfiguration = (UITableViewCell, String) -> ()
    var cellConfiguration: CellConfiguration

    init(items: [String], cellIdentifier: String, cellConfiguration: CellConfiguration) {
        self.items = items
        self.cellIdentifier = cellIdentifier
        self.cellConfiguration = cellConfiguration
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("Number of rows: \(self.items.count)")
        return self.items.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        print(__FUNCTION__)
        let cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier, forIndexPath: indexPath)
        self.cellConfiguration(cell, self.items[indexPath.row])
        return cell
    }
}
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let data = ["a", "b", "c"]
        let dataSource = SimpleListDataSource(items: data, cellIdentifier: "cell") { (cell, string) -> () in
            cell.textLabel?.text = string
        }

        self.tableView.dataSource = dataSource
        self.tableView.reloadData()
    }
}

问题是MessagesTableViewDataSource的实例被释放。UITableView上的委托和数据源属性较弱。您将数据源(MessagesTableViewDataSource)声明为函数中的局部变量,因此没有任何内容包含对MessagesTableViewDataSource实例的强引用

要解决此问题,请为dataSource定义一个实例变量,并在viewDidLoad中分配它

示例代码:

类消息ViewController:UIViewController,ManagedObjectContextSettable{

let dataSource: MessagesTableViewDataSource?
var managedObjectContext: NSManagedObjectContext!
@IBOutlet var messagesTableView: UITableView!

override func viewDidLoad() {
    setupMessagesTableView()
}

private func setupMessagesTableView() {
   dataSource = MessagesTableViewDataSource(managedObjectContext: managedObjectContext, conversationList: fetchedObjects as! [Conversation])
    // Assume fetchedObjects is an array fetched from CoreData store. I have removed the code that defines it for the purpose of this example.
    self.messagesTableView?.dataSource = dataSource
    self.messagesTableView?.delegate = dataSource
}

}

确保self.conversationList.count大于零。可能是因为conversationList正在后台线程中填充,而在显示tableView时未填充,在这种情况下,它的计数为零?我专门在DataSource类的init函数中向conversationList添加了一个实例,以避免该问题。我已经测试了conversationList.count的值,以确保它是1。可能不相关,但您应该使用
dequeueReusableCellWithIdentifier:forIndexPath:
(has forIndexPath),因为它永远不会返回nil。您当前的代码需要处理cell=nil。谢谢,我已经用fix编辑了上面的代码,请参见下面我的答案。您应该为dataSource声明一个实例变量,否则SimpleListDataSource的实例将被释放。