第 4 章
進階說明 Hello World App 的原理

Any fool can know. The point is to understand.

– Albert Einstein

你現在覺得開發一個 App 簡不簡單呢?我希望你會喜歡上建立自己的 App。

在我們繼續探索 iOS SDK 之前,我們稍微暫緩一下,來更仔細了解這個 Hello World App,這會有助於了解 iOS API 與 App 內部的運作原理。

到目前為止,你依照著步驟一步步建立了 Hello World App。整章讀完後,想必心中會出現了幾個疑問:

  • Storyboard 中的視圖控制器是如何與 ViewController.swift 檔內的 ViewController 類別建立連結?
  • showMessage(sender:) 方法中的那段程式碼是什麼意思呢?它要如何告知 iOS 顯示一個 Hello World 訊息?
  • @IBAction 這個關鍵字是做什麼用的?
  • 「Hello World」按鈕背後藏了什麼?按鈕是如何偵測到按下事件,並進而觸發 showMessage(sender:) 方法呢?
  • 什麼是 viewDidLoad() ?
  • 「Run」按鈕在 Xcode 中是如何運作的?所謂編譯一個 App 是什麼意思?

我想要你專注在探索與熟悉 Xcode 的開發環境,所以一開始沒有對以上的問題多做說明,然而了解程式碼背後運作的細節與掌握 iOS 程式的基礎觀念是有其必要性的。有些技術性的觀念或許有點難懂,尤其對於之前毫無程式開發背景的初學者而言更是。但是,其實不必擔心,這只是開始而已。當你照著後續的章節繼續學習來寫了更多的程式碼之後,你便會更了解 iOS 程式語言。你現在最需要做的一件事就是盡心學習。

了解實作與介面

在進一步深入理解程式觀念之前,我們從生活中舉個真實的例子來說明。

例如:電視遙控器,它可以很方便地以無線方式來遠端調整聲音。當想要更換頻道時, 則只要簡單地按下頻道號碼。而如果想要提高音量,也只要按下音量「+」按鈕即可。

請問你是否知道在按下音量按鈕或者頻道按鈕之後,背後發生了什麼事情嗎?我想大部分的人不知道也不明白遙控器與電視之間是如何進行無線溝通的。你可能會認為是遙控器送出某個訊息給電視,然後進一步啟動音量調整或者頻道切換。

在這個案例中,與你互動的按鈕一般定位為 介面 (interface),而隱藏在按鈕背後的細節就是實作(implementation )。介面與實作之間的溝通則是透過訊息。

圖 4-1. 以電視遙控器為例
圖 4-1. 以電視遙控器為例

這個觀念也可以應用在 iOS 程式世界中。在 Storyboard 中的使用者介面就是介面,而程式就是實作 。使用者介面(例如 按鈕)透過訊息與程式做溝通。

回到 Hello World 專案來說, 你在視圖中加入的按鈕就是所謂的「介面」。ViewController 類別的 showMessage(sender:) 方法就是「實作」。當某人按下按鈕,它會經由 showMessage(sender:) 的觸發來傳送一個 showMessageWithSender 訊息到 ViewController 類別。

剛剛述及的部分是物件導向程式設計(Object Oriented Programming )中一個很重要的觀念,稱為封裝(Encapsulation )showMessage(sender:) 方法的實作是隱藏於外面的世界(也就是介面)背後,「Hello World」按鈕並不清楚 showMessage(sender:) 方法是如何運作的。我們所要知道的是這個按鈕只負責傳遞訊息而已,而 showMessage(sender:) 方法接手處理剩下的工作,也就是呈現「Hello World」訊息在畫面上。

Quick note: 如同 Objective-C 一樣,Swift 是一個物件導向程式(OOP)語言,大部分一個 App 內的程式碼都是以某種方式在處理某種物件,但我不想在本章就以艱深的 OOP 的觀念來讓你困擾。只要我們繼續往前邁進,你將會學到更多關於物件導向程式設計的觀念。

觸控背後

現在你已經了解 UI 中的按鈕是經由某種訊息和程式碼進行溝通。讓我們來深入了解當使用者點選「Hello World」按鈕時,實際上發生了什麼事情呢?「Hello World」按鈕是如何呼叫 showMessage(sender:) 方法呢?

你還記得你已經將介面建構器中的 Hello World 按鈕與 showMessage(sender:) 事件建立連結了嗎?

請再次打開 Main.storyboard, 並且選擇「Hello World」按鈕, 在工具區點選「連結檢閱器」(Connection Inspector )。在 Sent Events 區塊,你可以找到一串可以取得的事件與相對應要呼叫的方法。在圖 4-2 中可以看到「Touch Up Inside」事件連結到 showMessage(sender:) 方法。

圖 4-2. 使用連結檢閱器顯示連結狀況
圖 4-2. 使用連結檢閱器顯示連結狀況

在 iOS 中,App 是以事件驅動的程式為基礎。不論是系統物件或 UI 物件,它監聽某個觸控事件來決定 App 的運作流程。以一個 UI 元件(例如:按鈕)來說,它可以監聽到特定的觸控事件。當這事件被觸發時,這個物件就會呼叫與這個事件關聯的預設方法。

在 Hello World App 中,當使用者的手指從按鈕內提起後,「Touch Up Inside」事件被觸發。結果,它呼叫了 showMessage(sender:) 方法來顯示「Hello World」訊息。我們使用「Touch Up Inside」事件取代「Touch Down」,是因為我們要避免偶發狀況或誤觸,圖 4-3 整理了整個事件的流程以及我所談及的內容。

圖 4-3. Hello World App 事件流程
圖 4-3. Hello World App 事件流程

深入了解 showMessage方法

現在你應該對 iOS 程式有了進一步的認識,不過在 showMessage(sender:) 方法內的程式碼區塊是什麼呢?

首先要知道的是,什麼是「方法」(method )?如同之前所提到的,App 中的程式碼多數是以某種方式在處理某種物件。每一個物件提供特定的功能與執行特定的任務(例如:在畫面上顯示訊息)。這些功能以程式碼來表達,即所謂的 方法」(method )

現在我們來更深入了解showMessage(sender:)方法,如圖 4-4 所示。

圖 4-4. 進一步解釋 showMessage() 方法
圖 4-4. 進一步解釋 showMessage() 方法

Quick note: 我知道對你來說,尤其是對程式碼完全不懂的人,要了解這段程式碼會有些許的困難,你需要花點時間來習慣物件導向程式設計,但不要就此放棄,只要繼續堅持,你將會逐漸了解物件、類別與方法。你可以參考附錄來學習 Swift 的語法
以 Swift 來說,在類別中宣告一個方法,會使用 func 關鍵字。func 關鍵字後面是接著方法名稱。名稱作為方法的識別,並且讓它容易在程式碼中任意被呼叫。有需要的話,方法可以帶入參數(parameter )。參數定義在括號內。每一個參數都有其名稱與型態,以冒號(:)來分開。以我們的例子來說,這個方法接受一個具有 UIButton 型態的 sender 參數。 此 sender 參數表示物件傳遞了需求。換句話說,它是告訴你 使用者已經按下按鈕了。

Note: 你記得前一章的作業 #2 嗎? 這個 sender 參數可以告訴你使用者按下了哪一個表情符號的按鈕 
一個方法不一定要帶入參數,這種情況下,你只要寫一對空括號即可,如下所示:

func showMessage()

還有一個在方法宣告中用到的關鍵字還沒討論到,就是 @IBAction 關鍵字,這可以讓你將程式原始碼與介面建構器的使用者介面物件做連結。當它被插入宣告的方法中,也就是將它公開給介面建構器的意思。因此,這就是第 3 章當你建立「Hello World」按鈕與程式碼之間的連結時,之所以會在彈出式選單中出現了showMessageWithSender 事件的原因。如果你仍然無法理解的話,請參考圖 3.20 便會明白了。

好的,方法的宣告就說明到這裡,我們討論一下大括號內的程式碼,這段程式碼實際上就是實踐方法所執行的任務。

如果你仔細看一下程式碼區塊的第一行,在這邊我們倚賴 UIAlertController 來建立 Hello World 訊息。而 UIAlertController 到底是什麼?又是從何而來的呢?

在開發 iOS App 的時候,我們不需要從頭撰寫所有的功能,例如:你不需要學會如何在畫面上畫出一個提示視窗。iOS SDK 已經綁進了許多內建的函數,可以讓開發工作更輕鬆些。這些函數稱為 API,是以所謂的 框架(framework )來組成,UIKit 框架就是其中一種,UIKit 框架提供了許多建構與管理你的 App 使用者介面的類別與函數。舉例來說, UIViewControllerUIButtinUIAlertController 就是來自於 UIKit 框架。

還有一件事要提醒你,在你使用任何框架中的函數時,你必須先匯入(import )它。也因此你會在 ViewController.swift 中的最前面看到這樣的敘述:

import UIKit

現在我們繼續來看一下 showMessage(sender:) 方法。

第一行程式碼是建立 UIAlertController 物件,然後將它儲存進 alertController。從類別建立物件的語法與方法呼叫非常相似。先指定類別名稱,接著設定一組屬性(Property ) 的初始值。這裡我們設定標題(Title )、顯示訊息(Message )與提示的樣式(Style ):

let alertController = UIAlertController(title: "Welcome to My First App", message: "Hello World", preferredStyle: UIAlertController.Style.alert)

建立完 UIAlertController 物件之後(也就是 alertController ),我們呼叫 addAction 方法來加入一個動作,以顯示「OK」按鈕的提示。在 Swift 中呼叫方法的程式寫法,是使用點語法(dot syntax )。

alertController.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))

你或許想知道要如何尋找一個類別的相關方法或用法。一個很簡單的方式是:閱讀文件。你可以至 Google 去查詢某個類別,而且 Xcode 提供一個很方便查詢 iOS SDK 文件的方式。

在 Xcode 中,你可以按下 option 鍵不放,然後在程式碼中將游標指向類別名稱(例如: UIAlertController )然後點擊,此時會彈出這個類別的敘述與程式範例,若是你需要進一步的資訊,往下捲動然後點選類別的參照連結,便會顯示這個類別的官方文件,如圖 4-5 所示。

圖 4-5. 類別資訊
圖 4-5. 類別資訊

UIAlertController 物件設定好後,最後一行程式碼是在畫面上顯示訊息。

present(alertController, animated: true, completion: nil)

因為要顯示提示訊息,我們要求目前的視圖控制器以動畫方式來呈現 alertController 物件。

有些時候,你能見到一些開發者以這樣的方式撰寫程式碼:

self.present(alertController, animated: true, completion: nil)

在Swift 中,self 屬性是參照至目前的實體(或者是物件),大部分的情況下,self 關鍵字是可以自己決定是否要放的,所以你可以省略它。

使用者介面與程式的關係

Xcode 是如何知道介面建構器(Interface Builder )中的視圖控制器(View Controller ) 與定義在ViewController.swift 中的 ViewController 類別連結在一起呢?

整件事情看似沒什麼,但其實不然,你還記得我們在建立 Xcode 專案時所選擇的模板嗎?也就是 Single View Application 模板。

當專案模板被使用後,它會自動在介面建構器中建立一個預設的視圖控制器,並且產生了 ViewController.swift。除此之外,這個視圖控制器自動連結定義在swift 檔中的 ViewController 類別(class )。

切換到 Main.Storyboard,並在文件大綱視圖選取「View Controller」。在工具區中,選擇「識別檢閱器」(Identity Inspector )圖示,你會看到 ViewController 被設定為「Custom Class」(自訂類別),這說明了在介面建構器中的物件為何與 Swift 程式碼內的類別有所關聯。

圖 4-6. 自訂類別(Custom Class )設定為「ViewController」
圖 4-6. 自訂類別(Custom Class )設定為「ViewController」

UIViewController 與視圖控制器的生命循環

你是否會對這部分感到疑惑呢?你知道自訂類別的名稱是 ViewController ,但是什麼是 UIViewController ?而什麼又是 viewDidLoad() 方法呢?為什麼這邊會出現這個方法?

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }


  .
  .
  .

}

如同我之前所說,我們倚賴 Apple 的 iOS SDK 來開發我們的 App。我們幾乎不會只為了讓一些提示訊息顯示在畫面上,而去寫繪製對話或訊息視窗的程式。我們也幾乎不會去寫繪製按鈕的程式。我們則是仰賴 UIAlertControllerUIButton 來處理這些繁重的工作。同樣的觀念也可以適用於視圖,這是呈現給使用者的長方形區域。

UIViewController 是 iOS App 的基礎模組。存放有UI 元件(例如按鈕)與顯示在畫面上的控制元件。預設的 UIViewController 有一個空的視圖。因為你已經在前一章做過測試,它只顯示空白畫面而沒有任何功能或與使用者之間的互動。要提供一個 UIViewController 的自定版本則是我們的工作。

為了這樣做,我們建立一個自 UIViewController 擴展而來的新類別(也就是 ViewController),因為是擴展自 UIViewControllerViewController 繼承了它的所有功能。舉例來說,它具有一個預設的空視圖。在程式中,它撰寫如下:

class ViewController: UIViewController

ViewController 中,我們提供了我們要客製化的內容。在這個 Hello World 範例,我們加上了一個稱作 showMessage(sender:) 的方法來呈現一個 Hello World 訊息。

這是你必須先記得的其中一項基礎的 iOS 開發觀念。我們不會全部都從頭寫起,這個 iOS SDK 已經提供給我們一個 iOS App 的架構。我們以這個架構為基礎來建立我們自己 App 的 UI 與功能。

現在我相信你已經有了 UIViewController 的基礎觀念,那麼,viewDidLoad 是什麼呢?

跟我們稍早討論的「Hello World」按鈕一樣,因為視圖可視度或狀態的改變,視圖控制器也接收了不同的事件。在適當的時間,iOS 在視圖的狀態改變時自動呼叫特定 UIViewController 的方法。

當視圖載入之後,viewDidLoad 將會自動呼叫,所以你可以執行一些其他的初始化設定。在 Hello World App,我們是保持不動。這邊快速舉個例子,你可以修改你的 Hello World App 的這個方法來測試一下:

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = UIColor.black

執行這個 App 來快速測試一下。視圖控制器的視圖的背景會變成黑色。這是當你要客製化 viewDidLoad() 方法時,眾多例子的其中一例。在稍後的章節,你將學會如何使用 viewDidLoad() 來做其他的客製化。 圖 4-7. 變更視圖的背景顏色

viewDidLoad 只是處理視圖狀態的其中一項方法。譬如說,當使用者按下 home 鍵來回到主畫面,viewWillDisappearviewDidDisappear 方法將會自動呼叫。同樣的,你可以自己提供這些方法的客製化內容來執行不同的操作。

Note: 你必須在「func viewDidLoad()」之前加上override 關鍵字 。這個方法原來是由 UIViewController 所提供,為了能夠客製化, 我們使用 override關鍵字來標示 要覆寫它預設的實作內容。

「執行」按鈕背後的動作原理

最後,我要談一下「執行」(Run)按鈕。當你點選「執行」(Run)按鈕時, Xcode 自動啟動模擬器(Simulator ),並且執行你的 App,不過,這背後發生了哪些事情呢?作為一個程式設計師,你必須要了解整個過程。

這整個程序可以被拆成三個階段:編譯(Compile)封裝(Package)執行(Run)

  • 編譯(Compile)– 或許你會認為 iOS 認識 Swift 程式碼, 實際上,iOS 只會讀取機器碼(Machine Code),Swift 程式碼只是供開發者撰寫與閱讀使用的。為了讓 iOS 認識 App 的原始碼,則必須經過一個轉譯的過程,將 Swift 程式碼轉成機器碼,而這個過程就稱作「編譯」, Xcode 已經有內建編譯器來轉譯程式碼。
  • 封裝(Package)– 除了原始碼之外,一個 App 通常會包含資源檔,像是圖片、文字檔、聲音檔等等。所有的資源檔皆會被封裝製作成最終的 App。我們通常把這兩個程序稱作「Build」,也就是建置程序,如圖 4-8 所示。
  • 執行(Run) – 這個動作實際上是啟動模擬器並載入你的 App。
圖 4-8. 建置程序
圖 4-8. 建置程序

本章小結

你應該對 Hello World App 的運作原理有了基本的概念,如果之前沒有程式開發的經驗,或許不易理解我們剛才討論的所有程式觀念。但是別擔心,只要你跟著本書之後的章節來練習撰寫更多的程式碼,並且開發真實的 App 後,你將會獲得更多 Swift 與 iOS 程式設計的概念。

如果你對本章有任何問題,隨時可以發問,你可以加上我們臉書的私密社團(https://facebook.com/groups/appcodatw)來詢問。

results matching ""

    No results matching ""