ios self.tableView.reloadData() 在 Swift 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24112844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
self.tableView.reloadData() not working in Swift
提问by chandlervdw
I'm attempting to learn Swift
& the basics of iOS
dev at the same time, so bear with me. I've got a TableViewController
that is firstly parsing a local JSON
file and rendering it's very simple data into TableViewCell
and SectionHeaderViews. Within the same TableViewController
, I'm making a call to a JSON
endpoint, which is returning data, which I am then setting to variables so I can access what I actually want to get at (the API structure is less than desirable). So, I finally set the proper data to be self.tableData
and then call self.tableView.reloadData()
but nothing happens. What gives?
我正在尝试同时学习Swift
和开发的基础知识iOS
,所以请耐心等待。我有一个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()
}
}
}
回答by noobular
You'll need to reload the table on the UI
thread via:
您需要UI
通过以下方式在线程上重新加载表:
//swift 2.3
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
//swift 5
DispatchQueue.main.async{
self.tableView.reloadData()
}
Follow up:
An easier alternative to the connection.start()
approach is to instead use NSURLConnection.sendAsynchronousRequest(...)
跟进:该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()
}
This doesn't allow you the flexibility of tracking the bytes though, for example you might want to calculate the progress of the download via bytesDownloaded/bytesNeeded
但是,这不允许您灵活地跟踪字节,例如,您可能希望通过 bytesDownloaded/bytesNeeded 计算下载进度
回答by user3752603
You have just to enter:
您只需输入:
First a IBOutlet:
首先是IBOutlet:
@IBOutlet var appsTableView : UITableView
Then in a Action func:
然后在一个动作函数中:
self.appsTableView.reloadData()
回答by Anand Suthar
If your connection is in background thread then you should update UI in main thread like this
如果您的连接在后台线程中,那么您应该像这样在主线程中更新 UI
self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true)
Swift 4:
斯威夫特 4:
self.tblMainTable.performSelector(onMainThread: #selector(UICollectionView.reloadData), with: nil, waitUntilDone: true)
回答by Dominique Lorre
In my case the table was updated correctly, but setNeedDisplay() was not called for the image so I mistakenly thought that the data was not reloaded.
在我的情况下,表已正确更新,但没有为图像调用 setNeedDisplay() 所以我错误地认为数据没有重新加载。
回答by Radu
Beside the obvious reloadData from UI/Main Thread (whatever Apple calls it), in my case, I had forgotten to also update the SECTIONS info. Therefor it did not detect any new sections!
除了来自 UI/主线程的明显 reloadData(无论 Apple 怎么称呼它),就我而言,我还忘记更新 SECTIONS 信息。因此它没有检测到任何新的部分!
回答by chandlervdw
So, the issue was that I was trying to inappropriately use @lazy, which caused my Business variable to essentially be a constant, and thusly uneditable. Also, instead of loading the local json, I'm now loading only the data returned from the API.
所以,问题是我试图不恰当地使用 @lazy,这导致我的 Business 变量本质上是一个常量,因此无法编辑。此外,我现在只加载从 API 返回的数据,而不是加载本地 json。
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()
}
}
}
You must always declare a lazy property as a variable (with the var keyword), because its initial value may not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.
您必须始终将惰性属性声明为变量(使用 var 关键字),因为在实例初始化完成之前可能无法检索其初始值。常量属性在初始化完成之前必须始终有一个值,因此不能声明为惰性。
回答by makkhokher
All the calls to UI should be asynchronous, anything you change on the UI like updating table or changing text label should be done from main thread. using DispatchQueue.main will add your operation to the queue on the main thread.
所有对 UI 的调用都应该是异步的,您在 UI 上的任何更改(例如更新表或更改文本标签)都应该从主线程完成。使用 DispatchQueue.main 会将您的操作添加到主线程上的队列中。
Swift 4
斯威夫特 4
DispatchQueue.main.async{
self.tableView.reloadData()
}
回答by iOS
You must reload your TableView in main thread only.Otherwise your app will be crashed or will be updated after some time. For every UI update it is recommended to use main thread.
您必须仅在主线程中重新加载 TableView 。否则您的应用程序将崩溃或将在一段时间后更新。对于每次 UI 更新,建议使用主线程。
//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()
})
}
回答by Said
Try it: tableView.reloadSections(IndexSet(integersIn: 0...0), with: .automatic) It helped me
试试看: tableView.reloadSections(IndexSet(integersIn: 0...0), with: .automatic) 它帮助了我
回答by Arjun
I was also facing the same issue, what I did wrong was that I'd forgot to add
我也面临同样的问题,我做错的是我忘了添加
tableView.delegate = self
tableView.dataSource = self
in the viewDidLoad() {} method. This could be one reason of self.tableView.reloadData() not working.
在 viewDidLoad() {} 方法中。这可能是 self.tableView.reloadData() 不工作的原因之一。