TableView reloadData() 不显示所有数据,即使带有值的数组已填充(swift)

Posted

技术标签:

【中文标题】TableView reloadData() 不显示所有数据,即使带有值的数组已填充(swift)【英文标题】:TableView reloadData() not showing all data, even though the array with values is filled (swift) 【发布时间】:2015-02-12 13:11:07 【问题描述】:

我有一个表格视图,其中填充了 http 调用的结果。数据被传递到名为tripTimes 的数组中。 triptimes 包含有关特定日期的某些旅行的信息。当天每趟行程的开始时间传入self.tableData,并插入到tableView中。

在此之后,我重新加载表格并...奇怪的结果。

数组tableData 被正确填充,但在我调用self.tableView.reloadData() 之后,几乎所有单元格都被正确填充。但是,第一个单元格是空的,直到我点击它或者我等待大约 5 秒并且最后一个单元格也是空的,但它在同一时间后获得与第一个单元格相同的值。

我认为它与 dispatch_async 部分有关,但我对 swift 和 ios 还很陌生,所以我不知道去哪里找。当我在dispatch_async 函数中打印self.tableData 的内容时,数组包含正确的值。

下面是我的viewController的代码

import UIKit
import Foundation
import SwiftHTTP
class TripSelect: UIViewController, UITableViewDataSource, UITableViewDelegate 

    @IBOutlet weak var dateTextField: UITextField!
    @IBOutlet weak var tableView: UITableView!

    @IBAction func showTrips(sender: AnyObject) 

        //if data is already present in tableData, empty it first
        if self.tripTimes.count != 0 && self.tableData.count != 0 
            for var i=0; i<self.tripTimes.count; i++ 
                self.tableData.removeObjectAtIndex(0)
                let indexPathToRemove = NSIndexPath(forRow: 0, inSection: 0)
                self.tableView.deleteRowsAtIndexPaths([indexPathToRemove], withRowAnimation: .Automatic)
            
            dispatch_async(dispatch_get_main_queue(), 
                self.tableView.reloadData()
            )
        
        var request = HTTPTask()
        request.GET("<MY_URL>", parameters: ["date": dateTextField.text], success: (response: HTTPResponse) in
            if let data = response.responseObject as? NSData 

                let str = NSString(data: data, encoding: NSUTF8StringEncoding) as String
                let str2 = "\"not enough data for this day\""

                if str != str2 
                    let json:AnyObject = JSON.parse(str)

                    self.dayLatLongs = json["dayLatLongs"] as Array
                    self.tripTimes = json["tripTimes"] as Array

                    var tripLatLongs:[AnyObject] = self.dayLatLongs[0] as Array
                    var firstTrip:[AnyObject] = tripLatLongs[0] as Array
                    var tripStartTime:String = ""
                    for var i=0; i<self.tripTimes.count; i++ 
                        tripStartTime = self.tripTimes[i]["startTime"] as String
                        //println("\(tripStartTime)")
                        self.tableData.addObject(tripStartTime)
                        let indexPath = NSIndexPath(forRow: 0, inSection: 0)
                        self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
                    
                    dispatch_async(dispatch_get_main_queue(), 
                        println(self.tableData)
                        self.tableView.reloadData()
                    )
                 else println(str)
            
            ,failure: (error: NSError, response: HTTPResponse?) in
                println("error: \(error)")
        )
    

    var dayLatLongs:[AnyObject] = []
    var tripTimes:[AnyObject] = []
    var tableData: NSMutableArray! = NSMutableArray()

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return self.tableData.count
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
        cell.textLabel?.text = self.tableData.objectAtIndex(indexPath.row) as? String
        return cell
    

    override func viewDidLoad() 
        super.viewDidLoad()
        var backgroundView = UIView(frame: CGRectZero)
        self.tableView.tableFooterView = backgroundView
        self.tableView.backgroundColor = UIColor.clearColor()
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    



更新:

var indexPaths:[NSIndexPath] = [NSIndexPath]()
for var i=0; i<self.tripTimes.count; i++ 
    tripStartTime = self.tripTimes[i]["startTime"] as String
    self.tableData.addObject(tripStartTime)
    indexPaths.append(NSIndexPath(forRow: i, inSection: 0))

self.tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)

现在结果显示正确,但只有在我“拖动”表格几次之后。

【问题讨论】:

success 块很可能在主线程上运行,因为 showTrips 似乎在主线程上被调用。无需在insertRowsAtIndexPathsdeleteRowsAtIndexPaths 之后使用reloadData,但您需要确保使用正确的索引插入和删除单元格,并且仅在主线程上:尝试使用所有索引填充数组并进行一次插入/删除调用以简化该过程。 好的,我尝试了其他方法(更新了我的问题),所以现在可以正确显示这些值,但只有在我“拖动”表格几次之后。 尝试对删除方法执行相同的操作,至于线程:您似乎确保只有对 reloadData 的调用在主线程上,对插入/删除调用执行相同的操作:从这个意义上说,它们与reloadData 非常相似,应该始终在主线程上调用。在这种情况下,reloadData 调用可能会被删除,因为表格会自动更新,您可能会弄乱动画。 非常感谢!这解决了问题:) 动画现在也正常显示了,非常好!我会发布一个答案,这样更容易找到 【参考方案1】:

您的问题出在第一个 if 子句中:

 if self.tripTimes.count != 0 && self.tableData.count != 0 
            for var i=0; i<self.tripTimes.count; i++ 
                self.tableData.removeObjectAtIndex(0)
                let indexPathToRemove = NSIndexPath(forRow: 0, inSection: 0)
                self.tableView.deleteRowsAtIndexPaths([indexPathToRemove], withRowAnimation: .Automatic)
            
            dispatch_async(dispatch_get_main_queue(), 
                self.tableView.reloadData()
            )
        

您总是只删除索引0 处的值,而不使用i。所以用你的索引i替换所有硬编码的0

 if self.tripTimes.count != 0 && self.tableData.count != 0 
            for var i=0; i<self.tripTimes.count; i++ 
                self.tableData.removeObjectAtIndex(i)
                let indexPathToRemove = NSIndexPath(forRow: i, inSection: 0)
                self.tableView.deleteRowsAtIndexPaths([indexPathToRemove], withRowAnimation: .Automatic)
            
            dispatch_async(dispatch_get_main_queue(), 
                self.tableView.reloadData()
            )
        

【讨论】:

感谢您的快速回答,尽管这不是问题。当我第一次填表时,程序不会执行那部分代码,因为self.tripTimes.countself.tableData.count 在那个时候都是0(我用println检查过)【参考方案2】:

这个答案的所有功劳归于@A-Live。

更新了建议的更改:

要删除单元格,我将函数更改为

dispatch_async(dispatch_get_main_queue(), 
    if self.tripTimes.count != 0 && self.tableData.count != 0 
        self.tableData = []
        self.tableView.deleteRowsAtIndexPaths(self.indexPaths, withRowAnimation: .Automatic)
        self.indexPaths = []
    
)

要添加单元格,我将函数更改为

dispatch_async(dispatch_get_main_queue(), 
    for var i=0; i<self.tripTimes.count; i++ 
        tripStartTime = self.tripTimes[i]["startTime"] as String
        self.tableData.addObject(tripStartTime)
        self.indexPaths.append(NSIndexPath(forRow: i, inSection: 0))
    
    self.tableView.insertRowsAtIndexPaths(self.indexPaths, withRowAnimation: .Automatic)
)

【讨论】:

很高兴它起作用了,最后一点:确保您在同一个线程上修改数据源,以使所有更新操作线程安全。在这种情况下,将循环和tableData = [] 移动到您已经拥有的 GCD 块内。否则,对showTrips 的后续调用可能会尝试在(可能)不同的分离线程上修改相同的数组(通常是数据源)。

以上是关于TableView reloadData() 不显示所有数据,即使带有值的数组已填充(swift)的主要内容,如果未能解决你的问题,请参考以下文章

ReloadData() 不刷新 TableView

使用通知中心和 tableview.reloaddata() 不刷新表视图

tableView.reloadData() 如何正确重新加载数据?

如何让 tableView.reloadData() 与核心数据正常工作?

reloadData() 不会更新父 TableView

UITableView.reloadData() 没有刷新 tableView。没有错误信息