微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Swift - 关闭 ViewController 后停止重新加载 TableView

如何解决Swift - 关闭 ViewController 后停止重新加载 TableView

我有一个获取请求完成后填充的表格视图。每行包含一个在 SFSafariViewController 中打开的链接。一旦用户点击 SF Safari VC 中的 Done 按钮,tableview 将重新加载并再次调用获取请求。我不希望这种情况发生,因为获取请求有时需要 15 秒以上的时间,而且恐怕会使我的 API 调用次数增加一倍。

下面的代码 - 一旦 Safari VC 被关闭,我能做些什么来防止重新加载 tableview?我尝试使用布尔值来跟踪它,但是当 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(_:) 方法检查布尔标志 refresh,并且仅在 refresh == true 时获取数据并重新加载表。但是,它明确设置了 refresh = true。每次您关闭其他视图控制器并重新显示表视图控制器时,您的 viewWillAppear(_:) 函数都会被调用。

将行 refresh = true 移动到 viewDidLoad()。问题解决了。 (viewDidLoad() 仅在首次创建视图控制器时调用一次,而不是每次通过解除/弹出覆盖它的视图控制器而被发现时调用。)


编辑:

注意在这段代码中:

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
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。