讓不懂程式設計的人愛上iPhone開發系列2 iOS12+Swift4.2版-Checklists-07
說明 :
本系列教程改編自raywenderlich.com中的iOS Apprentice系列,有需要的童鞋請移步到這裡購買英文版原教程: https:// store.raywenderlich.com /products/ios-apprentice
歡迎繼續我們的學習。
在上一課的內容中,我們成功的在介面中添加了一個表檢視,然後讓它顯示了幾行資料資訊。不過看起來是完全相同的,都是佔位文字”Label“。
接下來讓我們稍微做點調整,起碼讓每一行顯示的內容都不同吧。
將行資料新增到cell中
在Xcode中開啟storyboard⽂檔案,然後選擇table view cell中的標籤label。如果你怕選擇錯了,可以在左側的檢視元素列表中點選選擇。
然後在Xcode右側的⾯面板中切換到Attributes Inspector,將Tag這一欄的數值設定為1000.

設定這樣⼀個tag(標記)究竟有神⻢用處呢?通過tag標記我們可以給⽤使用者界⾯中的視覺元素設定一個 數字識別符號,這樣在後續需要使用到它的時候可以很容易找到。那麼這⾥為神⻢要設定為1000呢? 其實沒神⻢特別道理,只要這個數字不是0就行(因為0是標記的預設數值)。如果你願意,⽤你最習慣的1024也可以,你懂的~
注意:
⼀定要確定你的標記值是設定在標籤上。初學者最常犯的錯誤就是給table view cell設定了標記值,⽽不是給Label標籤設定。這樣最後的結果就不是你所期待的了。
接下來在Xcode中開啟ChecklistViewController.swift,更改tableView(_:cellForRowAt:)
方法的程式碼如下:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ChecklistItem", for: indexPath) //新增下面的程式碼 let label = cell.viewWithTag(1000) as! UILabel if indexPath.row == 0 { label.text = "流浪地球" } else if indexPath.row == 1{ label.text = "瘋狂的外星人" } else if indexPath.row == 2{ label.text = "飛馳人生" } else if indexPath.row == 3{ label.text = "喜劇之王" }else if indexPath.row == 4{ label.text = "小豬佩奇過大年" } //結束以上的新程式碼段 return cell }
在這個⽅法體中,第⼀行程式碼我們之前已經瞭解過了,它的作⽤就是獲取prototype cell的拷貝(不 管是新的還是回收利用的),然後把它賦予新建立的一個cell本地變數,其型別是
UITableViewCell。 接下來的就是新東西了,⾸先是這⼀⾏:
let label = cell.viewWithTag(1000) as! UILabel
這⾥我們請求獲取cell中的標記為1000的⼦檢視,這個標記就是我們剛才在storyboard中在標籤上所設定的。通過這種方法,我們就獲取了⼀個到該UILabel標籤物件的引⽤。 實際上,通過使⽤tag標記的⽅式來獲取到某個視覺元素的引⽤用是⾮常方便的,可以省掉了宣告 @IBOutlet變數的步驟。
思考:
好吧,為神⻢這⾥我們不在檢視控制器中新增⼀個IBOutlet屬性宣告,然後把cell的標籤和 storyboard中的outlet關聯在⼀起呢?
答案:
在table檢視中可能不⽌⼀個cell,⽽而個cell都會擁有⾃己的標籤。如果我們使用之前的⽅法,將prototype cell中的標籤和檢視控制器中的某個outlet關聯在⼀起,那麼該屬性只能指向其中⼀個cell的標籤,⽽不是所有。
需要注意的是,label標籤屬於cell的⼦檢視,⽽不是屬於檢視控制器,因此我們不能為它建立⼀個outlet。聽到這句話是不是有點糊塗?Don’t panic!不要恐慌~
在後續的教程中我們將繼續回到這個話題,但在這⾥就暫時別管了。
到底什麼是indexPath呢?
在上一課的內容中,我們教過大家一個小小的技巧。當你在Xcode的原始碼中看到某個方法、引數或屬性之前從來沒見過時,可以按下option鍵,然後點選關鍵詞檢視。
這個大概解釋下indexPath的作用。
簡單來說,它是指向表中某個特定行的物件。當表檢視為cell請求資料來源的時候,程式會檢視indexPath.row的⾏編號屬性,從 ⽽確定該cell需要哪⼀行資料。
在使⽤表檢視的時候,我們還有可能把不同的⾏放進section⾥面。⽐如在地址薄應用中,我們會使⽤姓來查詢聯絡⼈人。所有姓以A開頭的聯絡⼈人會被分到同⼀個section組中,⽽所有姓以B開頭的聯絡人會被放到另⼀個section組中,以此類推。 為了查詢某⼀行所屬的section,我們需要使⽤indexPath.section屬性。因為Checklists應⽤用不會⽤到這種分組方式,所以可以暫時忽略NSIndexPath的section屬性。
繼續回到程式碼。
接下來的⼏行程式碼應該不會讓你很頭大。
if indexPath.row == 0 { label.text = “觀看《流浪地球》” } else if indexPath.row == 1{ label.text = “觀看《瘋狂的外星人》” } else if indexPath.row == 2{ label.text = “觀看《飛馳人生》” } else if indexPath.row == 3{ label.text = “觀看《喜劇之王》” }else if indexPath.row == 4{ label.text = “觀看《小豬佩奇過大年》” }
之前我們已經學過if- else if -else的語法結構。這⾥程式檢查了indexPath.row的屬性值,其中包含了行編號,然後根據不同的⾏編號賦予標籤中的⽂本不同的值。
在這裡,我們列出了2019年春節賀歲檔要看的幾部熱門電影,作為重要的待辦事項~
作為一個鐵桿的科幻迷,當然是首推《流浪地球》了。

當然,要吐槽一下的是,《三體》究竟什麼時候可以拍出來呢?

需要特別注意的是,第⼀行的index屬性值是0,⽽不是1。
在程式世界裡,萬物從0開始。所有如果你的列表中有四個事項,那麼它們的編號是0,1,2和3。當然 這個有點反⼈人類,畢竟我們習慣了數⾃⼰的⼿指1,2,3,4。不過在程式世界⾥面就是這樣的。因 此,對於第⼀個section中的第⼀行,indexPath.row的值是0,⽽indexPath.section的值也是0.第⼆行的編號是1,第三行的編號是2,以此類推。
其實萬物從0開始也是符合陰陽太極理論的。⽼子⽈過:“道⽣一,⼀生⼆,⼆生三,三⽣萬物。” 這⾥的道可以看做0。
萬物負陰⽽抱陽,衝⽓以為和。0和1構成了變幻⽆窮的程式世界,豈不對應了陰陽?
當然,以上只是瞎掰,不要當真。
好了,現在可以運⾏應用,看看我們有哪些事情要做的~

可以看到,現在我們的時間管理軟體顯示了5件事情,也就是我們要看的5部賀歲片~
現在讓我們回顧一下如何使用tableView(_:cellForRowAt:) 為表檢視提供資料。
首先,我們需要獲取一個UITableViewCell物件。
然後,根據indexPath的行編號來更改cell中的內容。
小練習:
如果你閒得無聊,打算把這5部賀歲片反反覆覆看個幾十遍。那麼,現在可以嘗試著往表檢視中填充100行資料。
1.把tableView(_:numberOfRowsInSection:) 方法的返回值設定為100.
2.更改剛才所新增的設定label.text的相關程式碼如下:
if indexPath.row % 5 == 0 { label.text = "觀看《流浪地球》" } else if indexPath.row % 5 == 1{ label.text = "觀看《瘋狂的外星人》" } else if indexPath.row % 5 == 2{ label.text = "觀看《飛馳人生》" } else if indexPath.row % 5 == 3{ label.text = "觀看《喜劇之王》" }else if indexPath.row % 5 == 4{ label.text = "觀看《小豬佩奇過大年》" }
這⾥用到了模操作符 %,如果你的中⼩學數學還沒忘光光的話,可能對它還有⼏分印象。模操作其實就是返回除法計算的餘數。⽐如13 %4 =1,因為13除以4的結果是3.25,⽤整數來表示的話除法的結果是3,然後餘數是1.⽽12%4=0,因為沒有餘數。
這樣⼀來,第1⾏,第6⾏,第11⾏,第16⾏,等等都會顯示”觀看《流浪地球》”,第 2⾏行,第7⾏,第12⾏,等等都會顯⽰"觀看《瘋狂的外星人》”,以此類推。
想來你已經很清楚,每隔5⾏所顯示的⽂本內容都會再次重複。這⾥我們會顯示100⾏內容,如果你要搞上⼀⼤堆普通的if-else if -else也可以,但顯然我們可以使⽤模操作來簡化這個過程。
第⼀行: 0%5 = 0
第⼆行: 1%5 =1
第三行: 2%5 =2
第四行: 3%5 =3
第五行: 4%5 =4
第六行: 5%5 =0 (和第⼀行相同,從這裡開始所顯示的內容會開始迴圈)
第七⾏: 6%5 =1(和第⼆⾏相同)
第⼋行: 7%5 =2(和第三行相同)
第九行: 8%5 = 3(和第四⾏相同)
第⼗行: 9%5 = 4 (和第五行相同)
第⼗一⾏: 10%5 =0(和第⼀行相同,再次迴圈之前的內容) 第⼗二行: 11%5 =1 (和第⼆行相同)
。。。。。。 後⾯就不再折騰了,相信你百分百可以看懂了。
假如你還是看不懂,也沒關係,只要知道這⾥我們⽤了⼀個⼩小的技巧快速填滿了整個表。 運⾏應⽤,可以看到類似下⾯的界⾯:

小技巧:
如果你是在模擬器上進行測試,那麼可以按下滑鼠左鍵,然後上下拖動,就跟在真機上使用手指拖動一樣~但是如果不按下滑鼠左鍵,是沒辦法拖動的。
思考:
為了顯示這100行資料,我們⽤到了多少個table view cell呢?
答案:
100個?
錯!
顯而易見,100行資料,難道不是用100個cell嗎?
遺憾的是人類的直覺往往有誤導性,雖然我們有100⾏資料,但在螢幕上最多同時可以容納14個cell。
等等,哥剛才仔細數了數,不是隻有13個cell嗎?沒錯,如果表中的內容靜⽌,的確我們只看到13 個cell,但如果你上下滾動表檢視,會發現有時上⾯的cell還在顯⽰,⽽新的cell已經在底部出現了。 因此⾄少需要14個cell。
如果你滾動表檢視的速度⾜夠快,或許可能表檢視需要更多的臨時cell,這⼀點我不確定。不過這⼀點重要嗎?不重要嗎?是的,不重要。你只需要表檢視會替你完成這個任務就⾏了。我們要做的事情是,當表檢視需要⼀個cell的時候向它提供,同時⽤相應行的資料資訊來填滿這個cell就好了。
總之,通常來說所需要的cell比row要少。因為如果我們的應用為每一行資料都提供一個cell,iOS很快就會榨乾了iPhone或iPad的記憶體,哪怕你是最新最NB的可以秒殺MBP的iPad Pro也不行。哪怕你有成千上萬條資料,我們在螢幕上需要檢視的永遠也就那麼幾條十幾條而已,否則整個程式立馬就崩了~
現在可能你已經明白了為什麼UITableView表檢視把row和cell分的這麼請,row代表著資料,可能有成千上萬條甚至更多。而cell則是螢幕上視覺化的部分,最多也就那麼十來條而已。
奇怪的崩潰
很多童鞋在通過郵件、私信或者論壇提問的時候,都會提到同樣的一個問題:”為什麼我照著你的內容一步步操作,但是程式還是崩潰了?到底哪裡出了問題?“
在開發的過程中,有無數種原因可能導致程式崩潰。
而其中一種就是你可能無意中在程式碼中設定了一個breakpoint(斷點)。
斷點其實是個好東西,它可以幫助我們對程式碼進行除錯。使用斷點的方式是在原始碼的某一行或某幾行新增斷點,然後跳轉到Xcode的偵錯程式。當斷點發揮作用的時候,給你的感覺跟程式崩潰是一樣的,但實際上程式只是暫停而已。
下面我們看一看斷點到底是長什麼樣的。

如果你的應用突然崩潰了,然後原始碼的某一行上面出現了藍色的箭頭,那麼Don’t panic,你只是”觸發“了一個斷點而已。
有些時候我們會為了除錯的需要而設定斷點,但還有些時候是因為不小心誤操作而已,我也曾經犯過類似的錯誤~
移除斷點其實很簡單,只要按下滑鼠左鍵,把它向左拖出Xcode視窗就好了。
當然,還有一種方式就是點選這個斷點,那麼它會從藍色變成灰色。斷點仍然存在,只不過會暫停發揮作用。

好了,一下子學了這麼多,我們也該休息一下了。
我們下一課再見~
答疑說明:
1.為了方便大家對課程中的問題提問,建立了一個問答社群。大家後續有開發相關的問題請到課程答疑專區提問 http:// icode.fun/ask/forum.php
2.請大家在提問之前建議先看一下這個帖子: http:// icode.fun/ask/forum.php? mod=viewthread&tid=5&extra=page%3D1
聯絡方式:
QQ討論群:375143733
個人微信: iseedo
公眾號:icodefun
接下來當然是福利時刻了~