self.tableView.reloadData() не работает в Swift

Я пытаюсь научиться Swift и основы iOS Dev в то же время, так что терпите меня. у меня есть TableViewController это в первую очередь разбор местного JSON файл и рендеринг это очень простые данные в TableViewCell и SectionHeaderViews. В том же TableViewControllerЗвоню JSON конечная точка, которая возвращает данные, которые я затем устанавливаю в переменные, чтобы получить доступ к тому, к чему я на самом деле хочу добраться (структура API меньше, чем хотелось бы). Итак, я наконец установил правильные данные для self.tableData а затем позвоните self.tableView.reloadData() но ничего не происходит Что дает?

import UIKit

class BusinessTableViewController: UITableViewController {

    var data: NSMutableData = NSMutableData()
    var tableData: NSArray = NSArray()

    @lazy var Business: NSArray = {
        let pathTCT = NSBundle.mainBundle().pathForResource("TCT", ofType: "json")
        let data = NSData.dataWithContentsOfFile(pathTCT, options: nil, error: nil)
        return NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as NSArray
        }()

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.titleView = UIImageView(image: UIImage(named: "growler"))

        tableView.registerClass(BeerTableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.separatorStyle = .None

        fetchKimono()
    }

    override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
//        return Business.count
        return 1
    }

    override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
        let biz = Business[section] as NSDictionary
        let results = biz["results"] as NSDictionary
        let beers = results["collection1"] as NSArray
        return beers.count
    }

    override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
        let cell = tableView!.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath!) as BeerTableViewCell
        if let path = indexPath {
            let biz = Business[path.section] as NSDictionary
            let results = biz["results"] as NSDictionary
            let beers = results["collection1"] as NSArray
            let beer = beers[path.row] as NSDictionary

            cell.titleLabel.text = beer["BeerName"] as String
        }

        return cell
    }

    override func tableView(tableView: UITableView!, titleForHeaderInSection section: Int) -> String! {
        let biz = Business[section] as NSDictionary
        return biz["name"] as String
    }

    override func tableView(tableView: UITableView!, viewForHeaderInSection section: Int) -> UIView! {
        let biz = Business[section] as NSDictionary
        let view = LocationHeaderView()
        view.titleLabel.text = (biz["name"] as String).uppercaseString
        return view
    }

    override func tableView(tableView: UITableView!, heightForHeaderInSection section: Int) -> CGFloat {
        return 45
    }

    func fetchKimono() {
        var urlPath = "names have been changed to protect the innocent"
        var url: NSURL = NSURL(string: urlPath)
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)

        connection.start()
    }

    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
        // Recieved a new request, clear out the data object
        self.data = NSMutableData()
    }

    func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
        // Append the recieved chunk of data to our data object
        self.data.appendData(data)
    }

    func connectionDidFinishLoading(connection: NSURLConnection!) {
        // Request complete, self.data should now hold the resulting info
        // Convert the retrieved data in to an object through JSON deserialization
        var err: NSError
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options:    NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        var results: NSDictionary = jsonResult["results"] as NSDictionary
        var collection: NSArray = results["collection1"] as NSArray
        if jsonResult.count>0 && collection.count>0 {
            var results: NSArray = collection as NSArray
            self.tableData = results
            self.tableView.reloadData()
        }
    }
}

7 ответов

Вам нужно будет перезагрузить стол на UI поток через:

//swift 2.3
dispatch_async(dispatch_get_main_queue(), { () -> Void in
    self.tableView.reloadData()
})

//swift 3
DispatchQueue.main.async{
    self.tableView.reloadData()
}

Последующие действия: более легкая альтернатива connection.start() подход вместо этого использовать NSURLConnection.sendAsynchronousRequest(...)

//NSOperationQueue.mainQueue() is the main thread
NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: url), queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
    //check error
    var jsonError: NSError?
    let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &jsonError)
    //check jsonError
    self.collectionView?.reloadData()
}

Это не позволяет вам гибко отслеживать байты, хотя, например, вы можете рассчитать ход загрузки через bytesDownloaded/bytesNeeded

Вы просто должны ввести:

Первый IBOutlet:

@IBOutlet var appsTableView : UITableView

Затем в функции Action:

self.appsTableView.reloadData()

Если ваше соединение в фоновом потоке, то вы должны обновить пользовательский интерфейс в основном потоке, как это

self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true)

Как я уже упоминал здесь

В моем случае таблица была обновлена ​​правильно, но setNeedDisplay() не был вызван для изображения, поэтому я ошибочно подумал, что данные не были перезагружены.

Итак, проблема заключалась в том, что я пытался использовать @lazy ненадлежащим образом, в результате чего моя переменная Business была по существу постоянной, и, следовательно, недоступной для редактирования. Кроме того, вместо загрузки локального json, я загружаю только данные, возвращенные из API.

import UIKit

class BusinessTableViewController: UITableViewController {

    var data: NSMutableData = NSMutableData()
    var Business: NSMutableArray = NSMutableArray()

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.titleView = UIImageView(image: UIImage(named: "growler"))

        tableView.registerClass(BeerTableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.separatorStyle = .None

        fetchKimono()
    }

    override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
        return Business.count
    }

    override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
        if (Business.count > 0) {
            let biz = Business[section] as NSDictionary
            let beers = biz["results"] as NSArray
            return beers.count
        } else {
            return 0;
        }
    }

    override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
        let cell = tableView!.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath!) as BeerTableViewCell
        if let path = indexPath {
            let biz = Business[path.section] as NSDictionary
            let beers = biz["results"] as NSArray
            let beer = beers[path.row] as NSDictionary

            cell.titleLabel.text = beer["BeerName"] as String
        } else {
            cell.titleLabel.text = "Loading"
        }

        return cell
    }

    override func tableView(tableView: UITableView!, viewForHeaderInSection section: Int) -> UIView! {
        let view = LocationHeaderView()
        let biz = Business[section] as NSDictionary
        if (Business.count > 0) {
            let count = "\(Business.count)"
            view.titleLabel.text = (biz["name"] as String).uppercaseString
        }
        return view
    }

    override func tableView(tableView: UITableView!, heightForHeaderInSection section: Int) -> CGFloat {
        return 45
    }

    func fetchKimono() {
        var urlPath = "names have been removed to protect the innocent"
        var url: NSURL = NSURL(string: urlPath)
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)

        connection.start()
    }

    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
        // Recieved a new request, clear out the data object
        self.data = NSMutableData()
    }

    func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
        // Append the recieved chunk of data to our data object
        self.data.appendData(data)
    }

    func connectionDidFinishLoading(connection: NSURLConnection!) {
        // Request complete, self.data should now hold the resulting info
        // Convert the retrieved data in to an object through JSON deserialization
        var err: NSError
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        var results: NSDictionary = jsonResult["results"] as NSDictionary
        var collection: NSArray = results["collection1"] as NSArray
        if jsonResult.count>0 && collection.count>0 {
            Business = jsonResult
            tableView.reloadData()
        }
    }
}

Быстрые Документы на @lazy:

Вы всегда должны объявлять свойство lazy как переменную (с ключевым словом var), поскольку его начальное значение не может быть получено до тех пор, пока не завершится инициализация экземпляра. Константные свойства всегда должны иметь значение до завершения инициализации и поэтому не могут быть объявлены как ленивые.

Помимо очевидных данных reloadData из UI/Main Thread (как бы Apple это ни назвала), в моем случае я забыл также обновить информацию SECTIONS. Поэтому он не обнаружил никаких новых разделов!

Попробуйте: tableView.reloadSections(IndexSet(inteersIn: 0...0), с: .automatic) Мне помогло

Все вызовы пользовательского интерфейса должны быть асинхронными, все, что вы изменяете в пользовательском интерфейсе, например обновление таблицы или изменение текстовой метки, должно выполняться из основного потока. использование DispatchQueue.main добавит вашу операцию в очередь в главном потоке.

Swift 4

DispatchQueue.main.async{
    self.tableView.reloadData()
}

Вы должны перезагрузить ваш TableView только в основном потоке. В противном случае ваше приложение будет сбой или будет обновлено через некоторое время. Для каждого обновления пользовательского интерфейса рекомендуется использовать основной поток.

//To update UI only this below code is enough
//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()//Your tableView here
})

//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Call your function here
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time and update UI
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
    //If you want to do changes in UI use this
    DispatchQueue.main.async(execute: {
        //Update UI
        self.tableView.reloadData()
    })
}

Я также столкнулся с той же проблемой, что я сделал не так, так это то, что я забыл добавить

tableView.delegate = self    
tableView.dataSource = self

в методе viewDidLoad() {}. Это может быть одной из причин того, что self.tableView.reloadData() не работает.

Другие вопросы по тегам