从 UIDocument 获取单元格数据时,如何确保 UITableView 中显示的列表顺序
How to ensure the order of list shown in UITableView when getting data for cell from UIDocument
我的应用程序通过 FileManager 为 UITableView 中的每个单元格获取数据。单元格需要来自需要打开 UIDocument 对象的文件的数据。但是,打开完成处理程序中的代码似乎无法预测地执行,因此单元格不会按照我希望的顺序显示。
如何解决这个问题?如果有人提供任何线索,我将不胜感激。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
fetchCellsData()
}
func fetchCellsData() {
do {
let files = getUrlsOfFiles() //files in a certain order
for file in files {
let document = MyDocument(fileURL: file) //MyDocument subclassing UIDocument
//open to get data for cell
document.open { (success) in
if !success {
print("File not open at %@", file)
return
}
let data = populateCellData(document.fileInfo)
self.cellsData.append(data)
self.tableView.reloadData()
/// tried below also
// DispatchQueue.main.async {
// self.cellsData.append(data)
// self.tableView.reloadData()
// }
}
document.close(completionHandler: nil)
}
} catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
let fileInfo = cellsData[indexPath.row].fileInfo
//assign fileInfo into MyCell property
return cell
}
我希望单元格按照 'files' 的顺序呈现,但是,看起来顺序有点不可预测,假设这是由于 'cellForRowAt' 在它知道之前被调用的事实全套 'cellsData'.
来自 UIdocument
上的 Apple 文档。 Apple doc:
open(completionHandler:)
Opens a document asynchronously.
这意味着即使您以正确的顺序触发 document.open
,也无法保证 completionHandler
序列的顺序相同,这就是顺序为 的原因不可预测.
但是,您知道他们会最终全部完成。
你可以做的是:
1 - 将打开文档中的所有数据放入另一个列表
2 - order
这个列表根据你的需要
3 - 将此列表放入 cellsData
(我假设它绑定到您的 tableViesDatasource)
var allDatas: [/*your data type*/] = []
...
do {
// reset allDatas
allDatas = []
let files = getUrlsOfFiles()
for file in files {
let document = MyDocument(fileURL: file)
document.open { (success) in
if !success {
print("File not open at %@", file)
return
}
let data = populateCellData(document.fileInfo)
self.allDatas.append(data) // "buffer" list
self.tableView.reloadData()
}
document.close(completionHandler: nil)
}
} catch { ...
然后您将 cellsData
更改为计算的 属性,如下所示:
var cellsData: [/*your data type*/] {
get {
return allDatas.order( /* order in accordance to your needs */ )
}
}
这样,每次添加新数据时,列表在重新显示之前都是有序的。
讨论
这是关于代码状态的更简单的解决方案,但这可能不是总体首选解决方案。例如,在您的代码中,您每次 添加一个新值时 都重新加载您的表视图,因为您知道之后会添加更多数据,而这并没有得到优化。
我建议你阅读 Dispatch Group,这是一种等到你触发的所有异步操作完成后再执行某些操作(例如在此重新加载你的表视图)的方法案例)(读数:Raywenderlich tuts)
我的应用程序通过 FileManager 为 UITableView 中的每个单元格获取数据。单元格需要来自需要打开 UIDocument 对象的文件的数据。但是,打开完成处理程序中的代码似乎无法预测地执行,因此单元格不会按照我希望的顺序显示。
如何解决这个问题?如果有人提供任何线索,我将不胜感激。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
fetchCellsData()
}
func fetchCellsData() {
do {
let files = getUrlsOfFiles() //files in a certain order
for file in files {
let document = MyDocument(fileURL: file) //MyDocument subclassing UIDocument
//open to get data for cell
document.open { (success) in
if !success {
print("File not open at %@", file)
return
}
let data = populateCellData(document.fileInfo)
self.cellsData.append(data)
self.tableView.reloadData()
/// tried below also
// DispatchQueue.main.async {
// self.cellsData.append(data)
// self.tableView.reloadData()
// }
}
document.close(completionHandler: nil)
}
} catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
let fileInfo = cellsData[indexPath.row].fileInfo
//assign fileInfo into MyCell property
return cell
}
我希望单元格按照 'files' 的顺序呈现,但是,看起来顺序有点不可预测,假设这是由于 'cellForRowAt' 在它知道之前被调用的事实全套 'cellsData'.
来自 UIdocument
上的 Apple 文档。 Apple doc:
open(completionHandler:)
Opens a document asynchronously.
这意味着即使您以正确的顺序触发 document.open
,也无法保证 completionHandler
序列的顺序相同,这就是顺序为 的原因不可预测.
但是,您知道他们会最终全部完成。
你可以做的是:
1 - 将打开文档中的所有数据放入另一个列表
2 - order
这个列表根据你的需要
3 - 将此列表放入 cellsData
(我假设它绑定到您的 tableViesDatasource)
var allDatas: [/*your data type*/] = []
...
do {
// reset allDatas
allDatas = []
let files = getUrlsOfFiles()
for file in files {
let document = MyDocument(fileURL: file)
document.open { (success) in
if !success {
print("File not open at %@", file)
return
}
let data = populateCellData(document.fileInfo)
self.allDatas.append(data) // "buffer" list
self.tableView.reloadData()
}
document.close(completionHandler: nil)
}
} catch { ...
然后您将 cellsData
更改为计算的 属性,如下所示:
var cellsData: [/*your data type*/] {
get {
return allDatas.order( /* order in accordance to your needs */ )
}
}
这样,每次添加新数据时,列表在重新显示之前都是有序的。
讨论
这是关于代码状态的更简单的解决方案,但这可能不是总体首选解决方案。例如,在您的代码中,您每次 添加一个新值时 都重新加载您的表视图,因为您知道之后会添加更多数据,而这并没有得到优化。
我建议你阅读 Dispatch Group,这是一种等到你触发的所有异步操作完成后再执行某些操作(例如在此重新加载你的表视图)的方法案例)(读数:Raywenderlich tuts)