iOS Apprentice中文版-從0開始學iOS開發-第十三課

在清單中添加新的項目

目前為止,你的列表中僅包含幾個固定的行,但是我們這個app的目的是可以讓用戶創建屬于自己的列表。因此,你需要給予用戶自己添加項目的能力。

在這一小節你要增加一個叫做navigation bar(導航bar)的東西到app的頂部。這個bar有一個藍色的“?”按鈕,點擊后可以打開一個新的界面,使你可以為新的項目輸入名稱。

但你點擊“Done(完成)”按鈕后,新的項目會被增加到列表里。

點擊navigation bar上的?按鈕打開項目添加界面

展現一個新的界面用于添加項目是許多app的一個基本套路。一旦你學會這個技巧,你會離成熟的iOS開發者更進一步。

以下是你在這一節中要做的事情。

1、添加一個navigation controller(導航控制器)

2、將Add按鈕放入navigation bar

3、當你點擊Add按鈕時,偽造一些數據進去

4、通過滑動刪除一行

5、在添加項目的界面中使用戶可以輸入新項目的名稱

一如既往的,我們先將這些功能分解成小的步驟。當你將Add按鈕放入界面后,你先在代碼里偽造一條數據添加到列表中。與一次性寫完添加項目的代碼不同,我們會假裝很多東西已經存在了,僅僅是處理一小部分內容,然后一點點的擴充它。

當你偽造的數據可以成功的添加到列表中后,我們就可以開始真正把添加新項目這個界面做完了。

Navigation Controllers(導航控制器)

首先我們來添加這個navgation bar。你也許在對象庫(Object Library)中見過一個叫做Navigation Bar的東西。你可以把它拖出來,并且放置在屏幕的頂端。不過,我們這次不打算這樣做。

取而代之的是,你會用嵌入的方式將view controller添加到navigation controller內。

在iOS用戶界面組件中,navigation controller(導航控制器)的使用頻率可能是僅次于table view的。它是一種使你可以一個界面轉到另一個界面的東西:

導航控制的工作方式

UINavigationController會為你照顧絕大多數關于navigation bar的內容,這極大的提高了你的編程效率。navigation bar的中間有一個標題,和左邊的一個“back(返回)”按鈕用戶自動將用戶帶回之前的界面。你可以在右邊放入一個自定義的按鈕。

添加導航控制器是非常容易的。

打開Main.storyboard并且選擇Checklist View Controller(黃色圖標那個)。

在Xcode頂部的菜單中,選擇Editor -> Embed In -> Navigation Controller。

將view controller放入navigation controller中

這樣,界面建造器就添加了一個新的Navgation Controller場景并且將自己和view controller聯系起來。

現在navgation controller連接著你的view controller

當app啟動時,Checklist View Controller自動被放入Navigation Controller中。

運行app試試看。

現在app的頂部有了一個navigation bar

app在外觀上與之前唯一的不同就是頂部有了一個navigation bar。感謝這件事,狀態欄不再會覆蓋列表第一行的一部分了。

回到storyboard并且雙擊Checklist View Controller中的navigation bar來編輯navigation bar的標題(你需要雙擊大概是navigation bar的中間的位置,否則不會出現編輯內容,可以參考下面圖示的位置)。

將標題修改為Checklists。

改變navigation bar的標題

你現在所改變的,就是你選擇Embed In命令后自動添加的Navigation Item的對象。

這個Navigation Item對象包含標題及按鈕,當view controller被激活時它們就會展現在navigation bar中。每一個嵌入式的視圖都有它自己的Navigation Item用于配置在navigation bar顯示什么內容。

當navigation controller滑動一個新的view controller到屏幕上時,它會用這個新的view controller的Navigation Item代替原有navigation bar上的內容。

從對象庫中拖出一個Bar Button Item到navigation bar的右邊。

確認使用的是Checklist View Controller的navigation bar,而不是navigation controller!

Checklist View Controller的navigation bar

這個新按鈕默認的名稱叫做“Item”,但是我們想要的是一個?號。

選定這個按鈕,打開它的屬性檢查器,將System Item選項更改為Add。

Bar Button Item的屬性設置

如果你看一下System Item中的選項,你會看到這里有許多預置的按鈕類型:Add、Compose、Reply、Camera、等等。你可以在你自己的app中按照它們的含義使用它們。

例如,你不能在用于發送郵件的按鈕上使用一個攝像機圖標,不恰當的使用這些圖標會使你的app在審核時遇到極大的麻煩。

OK,我們又有了一個按鈕。如果你運行app,你會看到如下界面:

app中有了一個添加按鈕

當然,點擊這個什么都不會發生,因為你還沒有將它和動作方法連接起來。在接下來的短暫時間內,你會創建一個新的界面,就是“Add Item(添加新項目)”界面,并且通過點擊這個?號按鈕跳轉到這個界面。但是在這之前,你首先要學習如何在列表中添加新的一行。

我們來把這個?號按鈕連接到一個動作方法上。在這方面,你已經有了十足的經驗,我們前一個課程中多次有過這種操作,所以你應該很輕車熟路。

打開ChecklistViewController.swift,添加動作方法:

@IBAction func addItem() {
    }

暫時我們不用添加具體的內容進去,只需要將它和?按鈕連接起來。

打開storyboard,按住ctrl將?按鈕拖拽到Checklist View Controller上,如下圖所示:

拖拽按鈕到Checklist View Controller

或者,有個更加簡單的辦法,就是按住ctrl拖拽?按鈕到離你很近的一個黃色圓圈圖標上,見下圖:

另一個方法

實際上你可以拖拽按鈕到任何代表這個view controller的地方,而上面的方法,是最好的選擇。

放開鼠標后會彈出一個窗口,選擇Sent Actions分節下的addItem:

連接addItem動作方法

讓我們來給addItem()添加點內容,回到ChecklistViewController.swift,在這個方法中添加以下代碼:

@IBAction func addItem() {
        let newRowIndex = items.count
        
        let item = ChecklistItem()
        item.text = "I am a new row"
        item.checked = false
        items.append(item)
        
        let indexPath = IndexPath(row: newRowIndex,section: 0)
        let indexPaths = [indexPath]
        tableView.insertRows(at: indexPaths, with: .automatic)
    }

在這個方法內部你創建了一個新的Checklistitem對象,并且將它添加到數據模型(就是items數組)中。你同時也告訴table view,“我插入了一個新的行,你要更新一下數據”

我們來講講上面代碼的作用:

let newRowindex = items.count

你需要計算這個新添加的行在數組中的索引(index)編號。為了使table view能正確的更新新的一行,這個計算是必須的。

當app啟動時,數組中有5條數據,并且屏幕上也相應的顯示出5行。這5行的index分別是0,1,2,3,4,電腦是從0開始計數的,記得嗎?所以新增到數據中的數據它的index必然是5(itmes里有5條數據,所以items.count=5,count就是計算數組中元素的個數)。

換而言之,當你新增一行到table view中時,新的一行的indexpath一定和數組中的index是相等的。

你將新的一行的index放到一個局部常量newRowIndex中。因為它不會被變更,所以用作常量。

接下來的幾行,你就應該比較熟悉了:

        let item = ChecklistItem()
        item.text = "I am a new row"
        item.checked = false
        items.append(item)

我們之前在init?(coder)里見過他們。他們創建了一個新的ChecklistItem對象,并且將這個新的對象添加到數組中。

現在數據模型中有6個ChecklistItem對象了,它們都在items數組中。注意一下,此時newRowIndex仍然是5,而items.count已經是6了。這就是為什么你需要在添加新的一行前,先計算items.count的值并且存儲到newRowIndex中了。

只把新的ChecklistItem對象添加到數據模型的數組中是不夠的。你同時還要告訴table view把這個新的數據添加到新的cell上去,然后在一個新的行里展現它。

let indexPath = IndexPath(row: newRowIndex,section: 0)

和你之前知道的一樣,table view使用index-path來標示行號,所以首先你要使用一個IndexPath對象來標示這個新的行,這里用的就是newRowIndex的值。所以新的一行的index-path就是5。

接下來的一行創建了一個臨時的數組,用來保存剛才生成的indexPath:

let indexPaths = [indexPath]

你需要使用insertRows(at:with:)這個方法來告訴table view添加新的一行,但是注意這個方法的名稱Rows是復數,這意味著其實你可以通過這個方法,一次性添加許多行。

所以它的參數并不是一個單獨的IndexPath,而是一個包含index-path的數組。幸運的是創建一個包含index-path的數組是非常簡單的,我們只需要使用[]這對方括號就可以了,這對方括號的作用就是創建一個新的數組,而數組的類型就和方括號中的類型一致,這里我們就寫作[indexPath],這樣就是一個包含indexpath對象的數組了。

最后,你通知table view插入新的這一行,這里的“with: .automatic”參數的作用是:使table view插入新行時,閃現一個漂亮的小動畫。

tableView.insertRows(at: indexPaths, with: .automatic)

復習一下整個過程:

1、創建一個新的ChecklistItem對象

2、將這個新創建的對象添加到數據模型中

3、為它在table view插入一個新的cell

其實你也可以添加多行到表格中,可以自己試試。這些新的行當你點擊它們時,也可以觸發對勾符號的開關。而且不論你怎么上下滾動,對勾符號的狀態都會保持一致。

點擊?按鈕后會添加新的行上去

記住,你一定要同時添加數據模型和表格。當你發送insertRows(at: with:)到table view時,你的意思是:“嗨,表格,我的數據模型中有一些新的數據要你添加進去”

這是非常重要的!如果你忘記了告訴table view這里有新的數據,或者你告訴table view這里有新的數據,但是實際上你沒有將這些數據添加到數據模型中的話,你的app就會掛掉。數據模型與視圖必須保持同步。

練習:給新增加的行默認對勾符號的狀態。

刪除行

也許我們該給用戶刪除某些行的權利。

在iOS app中通常的操作方法是“滑動刪除”。你用手指將某一行從右往左滑,然后在在最后邊就會出現一個刪除按鈕。點擊一下這個按鈕就可以完成刪除,如果點擊了其他地方則取消這次操作。

通過滑動刪除某一行

這種滑動刪除是非常容易做的。

在ChecklistViewController.swift中添加下面這個方法,我建議把這個方法放在table view方法附近。

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        items.remove(at: indexPath.row)
        let indexPaths = [indexPath]
        tableView.deleteRows(at: indexPaths, with: .automatic)
    }

當你在你的視圖控制器中使用commitEditingStyle方法后,table view會自動激活滑動刪除功能。你要做的全部事情就是:

1、從數據模型中移除掉這條數據。

2、刪除table view中對應的行。

它和addItem()做的事情正好相反。你再一次使用了一個臨時數組保存index-path對象并且告訴table view刪除掉這一行。

運行app,試試效果。

??:釋放對象
當你操作item.remove(at:)時,并不僅僅是從Checklistitem中取出了這個值,而是永久的將它破壞掉了。
我們會在下一個課程中詳細的討論這件事,在這里我們只需要記住如果一個對象沒有任何引用,那么這個對象會被自動銷毀掉。當ChecklistItem對象進入數組時,這個數組就引用了它。
但是當你把ChecklistItem對象從數組里取出來時,這個引用就不存在了,并且這個對象也就被銷毀了。或者,以計算機的語言來講,它被釋放了。
一個對象被銷毀了意味著什么?每一個對象都占用計算機中的一點內存。當你創建一個對象的實例的時候,一塊內存就會被預占,用于保存這個對象的數據。
如果這個對象被釋放了,那么這塊內存也就被釋放了,可以用來存儲其他東西。被釋放掉的對象不再存在,并且再也無法被使用。
在早起的iOS版本中,你必須手動釋放這些內存。幸運的是,現在時代變得很快,Swift使用一種叫做自動引用計數(Automatic Reference Counting,簡寫為ARC)的機制來管理對象的生命周期,對你而言無須在記住哪里需要釋放它們。對我而言,不用去操心釋放內存,簡直太棒了!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容