我有一個名為 PostViewController 的 viewControl,它有一個 UITableView 的帖子。我還有一個名為 PostCell 的類,它定義了 UITableViewCell。我在 PostCell 中創建了一個名為 likeButtonClicked 的按鈕功能,以支持類似于 twitter 的帖子。
@IBAction func likesButtonClicked(_ sender: Any) { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "likeButtonClicked"), object: nil, userInfo: ["cell":self, "likesButton":likesButton!]) }
這是將單元格 indexPath 和按鈕名稱傳遞給 PostViewController。我需要 indexPath 將喜歡增加 1 和按鈕名稱以在帖子受到青睞時將其影像更改為粉紅色。
然后我訂閱了 PostViewController 的 viewDidLoad 中的通知。
NotificationCenter.default.addObserver(self, selector: #selector(postLiked), name: NSNotification.Name(rawValue: "likeButtonClicked"), object: nil)
然后我在同一個viewController中撰寫了這個函式
@objc func postLiked(notification: Notification){
if let cell = notification.userInfo?["cell"] as? UITableViewCell{
let likesButton = notification.userInfo?["likesButton"] as? SpringButton
if let indexPath = postsTableView.indexPath(for: cell){
let post = posts[indexPath.row]
postId = post.id
PostAPI.getPostById(postId: postId) { post in
//Check if the same post were already favoured.
if !self.liked || self.oldPostId != self.postId{
self.newLikes = post.likes 1
self.liked = true
self.oldPostId = self.postId
}else{
self.newLikes = self.newLikes - 1
self.liked = false
}
PostAPI.favourPost(postId: self.postId, likes: self.newLikes) {
PostAPI.getPostById(postId: self.postId) { postResponse in
let post = postResponse
self.posts[indexPath.row] = post
let cellNumber = IndexPath(row: indexPath.row, section: indexPath.section)
self.reloadRowData(cellNumber: cellNumber){
if !self.liked{
likesButton?.tintColor = .systemPink
}else{
likesButton?.tintColor = .darkGray
}
}
}
}
}
}
}
}
func reloadRowData(cellNumber: IndexPath, completion: @escaping () -> ()) {
self.postsTableView.reloadRows(at: [cellNumber], with: .none)
completion()
}
請告訴我為什么 postLiked 函式的最后 4 行在 reloadRowData 函式之前執行,這導致按鈕將其顏色變為粉紅色,然后當它應該保持粉紅色時立即回傳灰色。
任何幫助將不勝感激。謝謝你。
uj5u.com熱心網友回復:
我預計具體問題是您致電reloadRows. 正如檔案所指出的:
重新加載一行會導致表視圖向其資料源詢問該行的新單元格。該表在為舊行設定影片時為該新單元格設定影片。如果要提醒用戶單元格的值正在更改,請呼叫此方法。但是,如果通知用戶并不重要——也就是說,您只想更改單元格顯示的值——您可以獲取特定行的單元格并設定其新值。
所以這很可能會創建一個全新的單元格,然后后面的代碼會修改從表中洗掉的舊單元格。(所以你看到了變化,然后單元格被移除和替換。)
我會首先擺脫整個reloadRowData通話。
不過,一般來說,這段代碼很脆弱,我會重新設計它。單元格應根據資料自行設定色調顏色。您通常不應該進入一個單元格并操縱它的子視圖。當單元格被回收時(例如,當它滾動到螢屏外時),這會給您帶來問題。所有的配置都應該在 中完成cellForRow(at:),cell 應該觀察它的 Post 并在有變化時更新自己。
資料應該存在于模型中。視圖應該觀察模型并做出反應。模型不應進入視圖并操縱任何東西。
作為一個方面:你reloadRowData看起來很異步,但事實并非如此。沒有理由使用完成處理程式。它可以呼叫return。
uj5u.com熱心網友回復:
表視圖的.reloadRows(at:...)(和.reloadData())函式是異步行程。
因此,您的reloadRowData()func在表視圖實際重新加載行之前回傳。
這是一種相當不尋常的方法——既NotificationCenter用于您的單元格與控制器通信,也用于嘗試通過保持對按鈕的參考來更改按鈕的色調顏色。
應該cellForRowAt根據您的資料源設定 tint 顏色。
編輯
我對表視圖資料重新加載異步的描述具有誤導性。
我想說的是這個……
如果我更改我的資料,請呼叫.reloadData(),然后再次更改我的資料:
// set myData values
myData = ["You", "Say", "Hello"]
// call .reloadData here
tableView.reloadData()
// change myData values
myData = ["I", "Say", "Goodbye"]
即使我們在這些是 myData 的值時呼叫,表格視圖也不會顯示“You Say Hello”。.reloadData()
這是一個完整的簡單示例來演示:
class TestTableViewController: UITableViewController {
var myData: [String] = ["Some", "Song", "Lyrics"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "c")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "c", for: indexPath)
c.textLabel?.text = myData[indexPath.row]
return c
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// call my func when a row is selected
self.myReload()
}
func myReload() {
// set myData values
myData = ["You", "Say", "Hello"]
// call .reloadData here
tableView.reloadData()
// change myData values
myData = ["I", "Say", "Goodbye"]
// table view doesn't reload itself we exit this func
// so we'll get
// I
// Say
// Goodbye
}
}
因此,在 Rob Napier 在他的回答中描述的其他問題中,您的原始代碼試圖在表格重新加載其資料之前更改單元格中物件的色調顏色。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/427927.html
