[英]Closure does not run in the main thread in swift
我想在UITableViewCell上顯示一些圖像。 但是我遇到了fatal error: Index out of range
錯誤以下的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
}
在DispatchQueue.main.async{ ... }
包裝要在主隊列上運行的任何內容。
也就是說,您當前的方法可能無法奏效。 這個方法被大量調用。 當用戶滾動時,每當一個單元格即將出現在屏幕上時,就會調用此方法(在iOS 10中,有時會在它出現在屏幕上之前)。 單元格經常被回收,並且每次請求單元格時,您都會將數據附加到titleArray
和其他數組(它們可能不是有序的;它們可能已經被取出;這個數組不會在右邊結束訂購)。
您需要將有關單元格的所有數據移動到模型對象中,並移出視圖控制器。 不應該有titleArray
和urlArray
等。應該只有一篇Article
, Article
應該注意獲取自己並更新其屬性。 此方法的作用是從緩存中獲取正確的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
}
}
然后有一些模型出現這些:
class Model {
func article(at index: Int) -> Article {
if let article = lookupArticleInCache(at: index) {
return article
}
let article = createAndCachePlaceholderArticle(at: index)
article.refresh()
}
}
然后你的代碼看起來像:
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
}
您可以使用KVO或Swift Observables或ArticleDelegate
協議讓單元格觀察Article
。 當Article
更新時,單元格會自動更新。
同樣,有很多方法可以解決這個問題。 您可以擁有所有單元格共享的“PlaceHolderArticle”,當真正的文章進入時,單元格會替換整個內容(因此文章是不可變的而不是自我更新的)。 您可以使用Swift Talk描述的更通用的方法。 有很多方法。 但關鍵是有這個模型可以獨立於任何特定的UI更新自身,以及觀察模型並顯示其所擁有的UI(視圖,視圖控制器)。
如果您想要更多關於此主題的信息,請搜索“Massive View Controller”。 這是您目前正在使用的反模式的通用名稱。 有很多方法可以解決這個問題,所以不要認為你在其上閱讀的任何特定文章是“正確的方式”(人們已經提出了一些非常復雜,過於精細的解決方案)。 但所有這些都是基於將模型與UI分離。
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)
}
}
你必須為這個計算單獨的功能,並嘗試避免“ cellForRowAt ”中的任何計算功能
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.