ios - 嵌入容器中的 UITableView 不刷新

标签 ios xcode swift

简而言之,我想确定用户的位置,从源获取一些 JSON 数据(需要首先知道位置),然后根据返回的数据创建一个表。

我在 Xcode 7 中使用 Swift 有一个带有一个原型(prototype)单元的自定义 UITableView。当此 TableView 是初始 View 时,它加载得很好。

现在,我尝试 1)将其嵌入到另一个 UIView 的容器中,2)在数据发生变化时更新它。两者都不起作用...容器中的表格永远不会出现。我已经在这上面花了近一周的时间,现在有点疯狂(这是我的第一个 iOS 应用程序)。

我注意到的一些事情:

  1. reloadData、setNeedsDisplay 和 setNeedsLayout 似乎没有执行任何操作。
  2. cellForRowAtIndexPath 未被调用,但 numberOfRowsInSection 被调用。
  3. 我尝试从父 UIView 以及 TableViewController 调用第 1 条中列出的所有函数。

以下是当前代码的样子: View Controller :

import UIKit
import MapKit
import CoreLocation
var currentLatLong: String = ""



class ViewController: UIViewController, CLLocationManagerDelegate  {
    // global var for location
    let locationManager = CLLocationManager()
    var currentLocation = CLLocation()
    var lastLatLong: String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // get permission and user's location
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        if CLLocationManager.locationServicesEnabled() {
            locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
            locationManager.startUpdatingLocation() 
        } else {
            print("Location services are not enabled")
        }
    }

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

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            currentLocation = locations.last!
            currentLatLong = "\(currentLocation.coordinate.latitude)%2C\(currentLocation.coordinate.longitude)"
            if lastLatLong != currentLatLong {
                lastLatLong = currentLatLong
                NSNotificationCenter.defaultCenter().postNotificationName("updateOverview", object: nil)
                self.view.setNeedsDisplay()
                self.view.setNeedsLayout()
                print("Found user's location: \(location)")

            }
            //print("Found user's location: \(location)")
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
             print("Failed to find user's location: \(error.localizedDescription)")
        }
    }

UITableViewController:

import UIKit
import MapKit
import CoreLocation

class OverviewTableViewController: UITableViewController {

    var LocRepositories = [LocationJSON]()
    var TimesRepositories = [TimesJSON]()
    var retrieved = [dataModelDefn]()

    override func viewDidLoad() {
        super.viewDidLoad()


        NSNotificationCenter.defaultCenter().removeObserver(self, name: "updateOverview", object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "checkRes", name: "updateOverview", object: nil)


        // fetch location data

        let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
        dispatch_async(backgroundQueue, {
            self.getLocations()
            dispatch_async(dispatch_get_main_queue(), {self.tableView.reloadData()})
        })
    }

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

    // MARK: - Table view data source

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

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



    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        // initialize data & cell
        var cell = tableView.dequeueReusableCellWithIdentifier("EDOverviewCell", forIndexPath: indexPath) as! OverviewTableCell
        var rowData = retrieved[indexPath.row]


        /* update cell */

        // border for cell
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
        self.tableView.separatorColor = UIColor(red:(0/255.0), green:(128/255.0), blue:(128/255.0), alpha:1)


        // alternating row colors
        if indexPath.row % 2 == 0 {
            cell.backgroundColor = UIColor(red:(249/255.0), green:(238/255.0), blue:(188/255.0), alpha:0.5)
        }
        else{
            cell.backgroundColor = UIColor(red:(252/255.0), green:(244/255.0), blue:(220/255.0), alpha:0.5)
        }

        return cell
    }

    func checkRes()
    {
        // fetch new data because location available
        getLocations()
        //self.tableView.reloadData()
        //dispatch_async(dispatch_get_main_queue(),{ self.tableView.reloadData() })
    }

    func getLocations(){
         // fetch demographic/location info

        // abort call if no location
        if currentLatLong == "" {
            return
        }

        /* get JSON data */
    }
}

以下是我尝试模仿解决方案的一些相关问题: Loading data after one second in uitableview. Any alternate way to eliminate this delay

How to stop UITableView from loading until data has been fetched?

UITableView doesn't populate when waiting for CLLocationManagerDelegate 's didUpdateToLocation method on iPhone SDK

这是一篇很长的文章,但如果我遗漏了任何必要的细节,请告诉我。我感谢任何帮助。

最佳答案

您当前拥有以下代码:

    let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(backgroundQueue, {
        self.getLocations()
        dispatch_async(dispatch_get_main_queue(), {self.tableView.reloadData()})
    })

这将在后台线程中运行getLocations,然后在主线程上刷新表tableView。都好。然而,getLocations 本身会执行一个 JSON 调用(当前只是一个注释),这无疑也在另一个后台线程上运行。因此,getLocations 将几乎立即返回,远远早于 JSON 完成。

您应该将完成处理程序传递给 getLocations,并且当 JSON 完成时(在其完成处理程序中),调用您自己的完成处理程序。大致如下:

    let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(backgroundQueue, {
        self.getLocations(completion: {
            dispatch_async(dispatch_get_main_queue(), {
                self.tableView.reloadData()
            })
        })
    })

(我这里的大括号可能不匹配)。然后 getLocations 定义为:

func getLocations(completion completion: (() -> Void)){
     // fetch demographic/location info

    // abort call if no location
    if currentLatLong == "" {
        return
    }

    getTheJsonAndInItsCompletion(... success: {
        completion()
    })
}

实际的 JSON 实现将取决于您使用的库。

关于ios - 嵌入容器中的 UITableView 不刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35589996/

相关文章:

ios - 删除带条件的字典对象 - Firebase - Swift

xcode - 实现 NSService 方法

ios - 如何在 Swift 中验证 X509Certificate?

ios - 无法在 objective-c 中使用 class(swift)

ios - 如何在 React Native iOS 中发现内存泄漏?

xcode - 开发 Flutter iOS 插件包 - Xcode 项目中的 Pods 文件夹为空

iphone - 已完成在 iPhone 上运行

ios - 如何在 React Native 中实现 PageCurl(翻页)转换

ios - App Store Connect 屏幕截图的尺寸

swift - Swift Package Manager 在本地实用吗?