Swift - 关闭 A 后停止重新加载 TableView ViewController
Swift - Stop TableView Reloading After Dismissing A ViewController
我有一个在获取请求完成后填充的表视图。每行包含一个在 SFSafariViewController 中打开的 link。一旦用户点击 SF Safari VC 中的完成按钮,表格视图将重新加载并再次调用获取请求。我不希望这种情况发生,因为获取请求有时可能需要超过 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
,则只获取数据并重新加载 table。但是,它明确设置了 refresh = true
。每次您关闭其他视图控制器并重新显示 table 视图控制器时,都会调用您的 viewWillAppear(_:)
函数。
将行 refresh = true
移动到 viewDidLoad()
。问题解决了。 (viewDidLoad()
仅在首次创建视图控制器时调用一次,而不是每次被 dismissing/popping 覆盖它的视图控制器发现时调用。)
编辑:
请注意,在此代码中:
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
}
}
我有一个在获取请求完成后填充的表视图。每行包含一个在 SFSafariViewController 中打开的 link。一旦用户点击 SF Safari VC 中的完成按钮,表格视图将重新加载并再次调用获取请求。我不希望这种情况发生,因为获取请求有时可能需要超过 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
,则只获取数据并重新加载 table。但是,它明确设置了 refresh = true
。每次您关闭其他视图控制器并重新显示 table 视图控制器时,都会调用您的 viewWillAppear(_:)
函数。
将行 refresh = true
移动到 viewDidLoad()
。问题解决了。 (viewDidLoad()
仅在首次创建视图控制器时调用一次,而不是每次被 dismissing/popping 覆盖它的视图控制器发现时调用。)
编辑:
请注意,在此代码中:
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
}
}