簡體   English   中英

Swift - 關閉 ViewController 后停止 TableView 重新加載

[英]Swift - Stop TableView Reloading After Dismissing A ViewController

我有一個在獲取請求完成后填充的表格視圖。 每行包含一個在 SFSafariViewController 中打開的鏈接。 一旦用戶點擊 SF Safari VC 中的 Done 按鈕,tableview 就會重新加載並再次調用 fetch 請求。 我不希望這種情況發生,因為獲取請求有時可能需要 15 秒以上的時間,而且我擔心它會使我的 API 調用次數增加一倍。

下面的代碼 - 一旦 Safari VC 被解散,我能做些什么來防止 tableview 重新加載? 我嘗試使用 boolean 來跟蹤它,但是當 viewDidLoad /appear 被調用時它會再次更改。 我應該以某種方式在 viewdidload/appear 之外調用我的獲取請求嗎?

import SafariServices
import UIKit

class ArticlesTVC: UITableViewController, SFSafariViewControllerDelegate {

var articles = [Article]()

let cellId = "articleCell"

var refresh: Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    registerCell()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    
    refresh = true
    
    if refresh == true {
        DispatchQueue.main.async {
            self.fetchArticles()              
            self.refresh = false
        }
    }
   
}

func registerCell() { tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId) }

override func numberOfSections(in tableView: UITableView) -> Int { return 1 }

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {  return articles.count }

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
    
    let article = articles[indexPath.row]
    cell.textLabel?.text = article.title
    cell.detailTextLabel?.text = article.description
    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let article = articles[indexPath.row]
    loadArticle(articleURL: article.url!)
    
}

func loadArticle(articleURL: String) {
    if let url = URL(string: articleURL) {
       
        let vc = SFSafariViewController(url: url)
        
        vc.delegate = self
        present(vc, animated: true)
    }
}

func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
    dismiss(animated: true)
}

func fetchArticles() {
    
    let baseURL = "url removed for privacy"
    
    guard let url = URL(string: "\(baseURL)") else {
        print("url failed")
        return
    }
    
    let session = URLSession(configuration: .default)
    
    let task = session.dataTask(with: url) { data, response, error in
        
        if error != nil {
            print(error)
            return
        }
        
        if let safeData = data {
            self.parseJSON(data: safeData)
        }
        
    }.resume()
}

func parseJSON(data: Data) {
    let decoder = JSONDecoder()
    
    do {
        let decodedData = try decoder.decode(ArticleEnvelope.self, from: data)
        let newsArticles = decodedData.news
        for item in newsArticles {
            let title = item.title
            let description = item.description
            let url = item.url
            let image = item.image
            let published = item.published
            
            let article = Article(title: title, description: description, url: url, image: image, published: published)
            
            DispatchQueue.main.async {
                self.articles.append(article)
                self.tableView.reloadData()
            }
            
        }
        print("articles loaded successfully")
    } catch {
        print("Error decoding: \(error)")
    }
}

當然。 你已經完成了 90% 的路程。 您的viewWillAppear(_:)方法檢查 boolean 標志refresh ,並且僅在refresh == true時獲取數據並重新加載表。 但是,它明確設置refresh = true 每次關閉其他視圖 controller 並重新顯示表格視圖 controller 時,都會調用您的viewWillAppear(_:) function。

將行refresh = true移動到viewDidLoad()中。 問題解決了。 viewDidLoad()僅在第一次創建視圖 controller 時調用一次,而不是每次通過關閉/彈出覆蓋它的視圖 controller 來發現它。)


編輯:

請注意,在此代碼中:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    
    refresh = true
    
    if refresh == true {
        DispatchQueue.main.async { //This bit is not needed
            self.fetchArticles()              
            self.refresh = false
        }
    }
}

不需要調用DispatchQueue.main.async ,這會使獲取數據的速度稍慢一些。 viewWillAppear(_:)總是在主線程上調用。

像這樣重寫它:

override func viewDidLoad() {
    super.viewDidLoad()
    registerCell()
    refresh = true //Moved from viewWillAppear
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    
    //Remove refresh = true from this function.

    if refresh == true {
        //No need to use DispatchQueue.main.async here
        self.fetchArticles()              
        self.refresh = false
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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