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 как переменную (с ключевым словом 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() не работает.