Swift - TableViewCell deletion programmatically
前言:
至於要在MyCell執行deleteCell()要怎麼做?很簡單,只要在MyCell給定一個MyTableViewController的變數,先將其設為Optional:
修改MyCell裡的handleAction():
將print("tapped")刪除,並加入
用來刪除自己(參數帶入self)
這樣就完成了嗎?不!
你可以在myTableViewController?.deleteCell(cell: self)設下breakpoint,並執行。
接著在模擬器或實機按下cell旁的delete按鈕,可以在debug area看到myTableViewController的值為nil:
Why? 因為我們在
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
這個函式內,沒有賦值給myCell裡的myTableViewController變數,所以修改tableView(_:, cellForRowAt:)這個函式裡的內容:
接著要驗證按下Delete按鈕後,控制流程是否正確,我們先移除剛剛handleAction()的breakpoint,接著在deleteCell()處設下中斷點,並執行。
然後按下模擬器或實機上cell的Delete按鈕,如果會出現下圖這樣正常觸發,恭喜你,目前為止大致做對了!
下一步是要呼叫刪除特定列的函式。我們在deleteCell()函式內呼叫這樣的一個函式:
至於參數的傳入,根據Apple Developer Documentation對此一函式的說明文件:
好的,現在就要來給定刪除的索引列,至於要取得當前刪除的列,我們可以用indexPathForCell()這個函式取得當前列,故將整個deleteCell()函式修改如下:
接著執行看看。
.
.
咦?怎麼crash了
不對呀,我刪除的函式有被呼叫到,也沒有丟錯參數,怎麼會錯呢?
哦! 我想到了
我刪除某一列的時候,那整個TableView的Cell內容是不是就也要跟著刪除?
是的,當我們執行上面的deleteRows()之後,事實上只剩下2個cell可以顯示內容,而我們最初的items共有3個項目(也就是第13行建立的items陣列),3個項目怎麼可以塞進2個cell呢?當然不行啊,況且我的目的是要連同cell的內容一併刪除,所以要在deleteRows()執行之前,先找出items陣列欲刪除的某一筆資料,換句話說就是要刪除某一cell所對應的items陣列索引內的某一筆資料,故我們要再次修改deleteCell()函式內容如下:
再執行一次,是不是可以順利刪除資料了呢?
可以的話,恭喜你學到一課 Woh~ nice !
大學畢業了,在前往研究所之路的過渡期,雖然心裡想著這是我最後一個暑假,應該要好好玩、大力玩,但是心裡總有一點聲音在警惕自己不要虛度這年輕寶貴的時刻,所以老樣子,承襲每年放寒暑假的傳統,self-learning iOS is still my main task to do !
其實以往都有在持續(或是說斷斷續續)跟Swift培養感情,但是礙於自己蠻懶的,一方面學的比較沒那麼積極、一方面部落格也就沒什麼在寫,所以趁現在剛學到一個新概念,趕緊花時間記錄下來,至於今天的主題也寫在標題上了,要來紀錄如何用手刻(programmatically)讓UITableViewCell從UITableView進行刪除的動作。
這也是我第一次用刻UI的方式做整個小專案的練習,以前Storyboard用久了,順便利用這個暑假學習純code來開發一個app。
而今天的教學資源來自Let's build that app這個頻道的這個影片中的一部份實作內容,我follow這個頻道也算蠻久了,無聊就會找這個講師的影片配飯看、照三餐看(誤),我只能說這個講師非常厲害,好啦,廢話不多說,我們趕快開始吧!
正文:
首先,請到我的Github下載原始專案:
打開之後,修改一下Identity,並執行:
可以看到已經有3列的cell,且每個cell除了有顯示label name (item 1, item 2, item 3),還各自有一個delete按鈕,我們要做的就是在按下delete之後,會將對應列的cell刪除。
沒有問題後,我們要建立一個刪除UITableViewCell的動作,所以我們寫一個函式在MyTableViewController的class內:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyTableViewController: UITableViewController { | |
///略 | |
//刪除UITableViewCell | |
func deleteCell(cell: UITableViewCell) { | |
} | |
} |
至於要在MyCell執行deleteCell()要怎麼做?很簡單,只要在MyCell給定一個MyTableViewController的變數,先將其設為Optional:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyCell: UITableViewCell { | |
var myTableViewController: MyTableViewController? | |
} |
修改MyCell裡的handleAction():
將print("tapped")刪除,並加入
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyCell: UITableViewCell { | |
//...略 | |
@objc func handleAction() { | |
myTableViewController?.deleteCell(cell: self) | |
} | |
} |
用來刪除自己(參數帶入self)
這樣就完成了嗎?不!
你可以在myTableViewController?.deleteCell(cell: self)設下breakpoint,並執行。
接著在模擬器或實機按下cell旁的delete按鈕,可以在debug area看到myTableViewController的值為nil:
Why? 因為我們在
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
myCell.nameLabel.text = items[indexPath.row]
return myCell
}這個函式內,沒有賦值給myCell裡的myTableViewController變數,所以修改tableView(_:, cellForRowAt:)這個函式裡的內容:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyTableViewController: UITableViewController { | |
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let myCell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell | |
myCell.nameLabel.text = items[indexPath.row] | |
//加入下面這一行 | |
myCell.myTableViewController = self | |
return myCell | |
} | |
} |
接著要驗證按下Delete按鈕後,控制流程是否正確,我們先移除剛剛handleAction()的breakpoint,接著在deleteCell()處設下中斷點,並執行。
然後按下模擬器或實機上cell的Delete按鈕,如果會出現下圖這樣正常觸發,恭喜你,目前為止大致做對了!
下一步是要呼叫刪除特定列的函式。我們在deleteCell()函式內呼叫這樣的一個函式:
至於參數的傳入,根據Apple Developer Documentation對此一函式的說明文件:
好的,現在就要來給定刪除的索引列,至於要取得當前刪除的列,我們可以用indexPathForCell()這個函式取得當前列,故將整個deleteCell()函式修改如下:
接著執行看看。
.
.
咦?怎麼crash了
不對呀,我刪除的函式有被呼叫到,也沒有丟錯參數,怎麼會錯呢?
哦! 我想到了
我刪除某一列的時候,那整個TableView的Cell內容是不是就也要跟著刪除?
是的,當我們執行上面的deleteRows()之後,事實上只剩下2個cell可以顯示內容,而我們最初的items共有3個項目(也就是第13行建立的items陣列),3個項目怎麼可以塞進2個cell呢?當然不行啊,況且我的目的是要連同cell的內容一併刪除,所以要在deleteRows()執行之前,先找出items陣列欲刪除的某一筆資料,換句話說就是要刪除某一cell所對應的items陣列索引內的某一筆資料,故我們要再次修改deleteCell()函式內容如下:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyTableViewController: UITableViewController { | |
var items = ["item 1", "item 2", "item 3"] //請將let改為var,藉此允許修改items內容 | |
func deleteCell(cell: UITableViewCell) { | |
if let deletionIndexPath = tableView.indexPath(for: cell) { | |
items.remove(at: deletionIndexPath.row) | |
tableView.deleteRows(at: [deletionIndexPath], with: .automatic) | |
} | |
} | |
} |
再執行一次,是不是可以順利刪除資料了呢?
可以的話,恭喜你學到一課 Woh~ nice !
留言
張貼留言