簡體   English   中英

Closure不會在swift的主線程中運行

[英]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和其他數組(它們可能不是有序的;它們可能已經被取出;這個數組不會在右邊結束訂購)。

您需要將有關單元格的所有數據移動到模型對象中,並移出視圖控制器。 不應該有titleArrayurlArray等。應該只有一篇ArticleArticle應該注意獲取自己並更新其屬性。 此方法的作用是從緩存中獲取正確的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 ObservablesArticleDelegate協議讓單元格觀察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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM