我试图学习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()
}
}
}
答案 0 :(得分:153)
您需要通过以下方式在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计算下载进度
答案 1 :(得分:21)
您只需输入:
首先是IBOutlet:
@IBOutlet var appsTableView : UITableView
然后在Action func:
self.appsTableView.reloadData()
答案 2 :(得分:4)
如果您的连接是在后台线程中,那么您应该像这样更新主线程中的UI
self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true)
斯威夫特4:
self.tblMainTable.performSelector(onMainThread: #selector(UICollectionView.reloadData), with: nil, waitUntilDone: true)
答案 3 :(得分:2)
在我的情况下,表格已正确更新,但没有为图像调用setNeedDisplay(),因此我错误地认为数据未重新加载。
答案 4 :(得分:1)
所以,问题是我试图不恰当地使用@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()
}
}
}
必须始终将lazy属性声明为变量(使用var关键字),因为在实例初始化完成之后才可能检索其初始值。常量属性在初始化完成之前必须始终具有值,因此不能声明为惰性。
答案 5 :(得分:1)
除了来自UI /主线程的明显reloadData(无论Apple称之为什么),在我的情况下,我忘记了也更新了SECTIONS信息。因此它没有检测到任何新的部分!
答案 6 :(得分:0)
对UI的所有调用都应该是异步的,在UI上更改的任何内容(如更新表或更改文本标签)都应该从主线程完成。 使用DispatchQueue.main会将您的操作添加到主线程上的队列中。
Swift 4
DispatchQueue.main.async{
self.tableView.reloadData()
}
答案 7 :(得分:0)
您必须仅在主线程中重新加载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()
})
}
答案 8 :(得分:0)
尝试一下:tableView.reloadSections(IndexSet(integersIn:0 ... 0),带有:.automatic)它对我有帮助
答案 9 :(得分:-1)
我也面临着同样的问题,我做错了是我忘记添加
tableView.delegate = self
tableView.dataSource = self
在viewDidLoad(){}方法中。这可能是self.tableView.reloadData()无法正常工作的原因之一。