tek*_*kun 1 multithreading ios swift
我想在 UITableViewCell 上显示一些图像。但是我在下面遇到错误
fatal error: Index out of range。问题是闭包可能不会在主线程中运行。我该如何解决这个问题?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PickupTableViewCell", for: indexPath) as! PickupTableViewCell
APIManager.getAnotherArticle{ (articles: Array<Article>?) in
for info in articles! {
self.authorArray.append(info.author)
self.descriptionArray.append(info.description)
if info.publishedAt != nil {
self.publishedAtArray.append(info.publishedAt)
}
self.titleArray.append(info.title)
self.urlArray.append(info.url)
self.urlToImageArray.append(info.urlToImage)
print(self.authorArray)
}
}
let program = urlToImageArray[indexPath.row] //index out of range
let urlToImage = NSURL(string: program)
cell.pickupImageView.sd_setImage(with: urlToImage as URL!)
return cell
}
Run Code Online (Sandbox Code Playgroud)
将您想要在主队列上运行的任何内容包装在DispatchQueue.main.async{ ... }.
也就是说,您目前的方法可能行不通。这个方法被调用了很多。当用户滚动时,每次单元格即将出现在屏幕上时都会调用此方法(在 iOS 10 中,有时会在它出现在屏幕上之前)。单元格经常被回收,titleArray每次请求单元格时,您都会将数据附加到和其他数组中(它们可能没有按顺序排列;它们可能已经被提取;这个数组不会以正确的顺序结束) )。
您需要将有关单元格的所有数据移入模型对象并移出视图控制器。不应该有 atitleArray和 anurlArray等。应该只有 an Article,并且 theArticle应该负责获取自身并更新其属性。这个方法的工作是Article从你的缓存中获取正确的,或者根据需要创建一个新的,并将它分配给一个ArticleCell. 本ArticleCell应该观看Article和更新本身的任何时间Article改变时(即当抓取完成)。几乎没有工作应该直接在这个方法中发生,因为它经常被调用,而且可能是随机的。
构建这种东西的常用方法是使用一个简单的模型对象(通常是一个引用类型,因此可以观察它;还有许多其他方法允许使用结构体,但它们更高级一些,因此我们将保留它简单的):
class Article {
var author: String
var description: String
var publishedAt: Date
var title: String
var url: URL
var image: UIImage
func refresh() {
// fetch data from server and replace all the placeholder data
}
}
Run Code Online (Sandbox Code Playgroud)
然后有某种模型可以出售这些:
class Model {
func article(at index: Int) -> Article {
if let article = lookupArticleInCache(at: index) {
return article
}
let article = createAndCachePlaceholderArticle(at: index)
article.refresh()
}
}
Run Code Online (Sandbox Code Playgroud)
然后你的代码看起来像:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PickupTableViewCell", for: indexPath) as! PickupTableViewCell
cell.article = sharedModel.article(at: indexPath.row)
return cell
}
Run Code Online (Sandbox Code Playgroud)
您可以使用 KVO 或Swift Observables或ArticleDelegate协议让单元观察Article. 当Article更新时,单元更新自身。
同样,有很多方法可以解决这个问题。您可以拥有一个所有单元格共享的“PlaceHolderArticle”,当真正的文章进入时,单元格会替换整个内容(因此文章是不可变的而不是自我更新的)。您可以使用Swift Talk描述的更通用的方法。有很多方法。但关键是有这个模型可以自我更新,独立于任何特定的 UI,还有一个 UI(视图、视图控制器)可以观察模型并显示它所拥有的内容。
如果您想了解更多关于此主题的信息,请搜索“Massive View Controller”。这是您当前使用的反模式的通用名称。有很多方法可以解决这个问题,所以不要假设你读到的任何特定文章都是“正确的方法”(人们已经提出了一些非常精细和过度阐述的解决方案)。但所有这些都是基于将模型与 UI 分离。
| 归档时间: |
|
| 查看次数: |
1739 次 |
| 最近记录: |