2014年1月7日 星期二

[CS193P] 1. Class Logistics, Overview of iOS, MVC, Objective-C

MVC (Model / View / Controller)

MVC一直是這五、六年來我非常推崇的開發觀念,早期從Java的Spring MVC開始著手,就深深愛上這種UI與程式邏輯獨立的開發方式。在iOS的開發裡,更是非常徹底的實踐了MVC。當然MVC有多種不同的變型,在此處的MVC我們可以簡單的來說明:

掌管UI背後運作的程式碼為Controller(在iOS開發,會稱為ViewController),是MVC中的運作核心。Controller掌控了最主要App流程的運作,除了接收使用者透過UI(View)傳遞而來的操作應如何有對應的動作,以及向Model端取得資料與商業邏輯的運算,再將運算結果反饋回UI做畫面上的改變。

而在iOS中的View,若開發的是Universal(可用於iPhone與iPad,但可依其不同特性而有不同的UI展現方式,但背後邏輯是相同一套Controller和Model),則可搭配兩個storyboard(一個iPhone用,一個iPad用,每個storyboard中由多個View所組成)呈現不同的UI。

這個設計方法說實話,有其優點也有其缺點,優點是真正落實了MVC的彈性,針對不同的顯示方式只要分開設計,可簡單搭配同一組背後的邏輯運算,而且可產生成相同的一套App,使用者不論是iPhone或是iPad,安裝後會以對應的UI來呈現。但缺點是兩種View若是有絕大部份都是相同的設計(90%),但卻要分兩個storyboard來設計,雖然可用copy/paste將大部份的UI元件複製再調整,但若當App愈來愈複雜時,若要調整某個既有的View的元件時,也得兩邊都更動,就UI模組化的觀念來看,改一處就要改多處(若有設計多國語言的storyboard,會更惱人),對UI人員是一種不會太開心的作業方式。

不過在iOS的View的獨立性,的確是相當的出色。若寫過.Net的話,應該會了解要讓Controller與View溝通,要在View上對每個元件都指定ID,好讓Controller可以針對ID來做事。但在Xcode優異的IDE介面,View上的元件與Controller之間是以「連線」的概念將兩者關聯起來,若View元件需有操作事件要指派delegate給Controller,只需要用肉眼直覺將該元件拖曳至Controller程式碼中建立IBAction關聯;而若有到時Controller需要修改UI元件內容屬性,也只需要將該元件拖曳至程式碼建立IBOutlet關聯。但在View當中,仍然沒有ID的觀念,只有從Xcode GUI上才看得出到底是哪個元件連到哪個Controller的屬性或方法上,而且沒有要用的就不必做連線。這點和其他開發環境上是有蠻大的差異,但做法相當直覺且先進。

總之,在iOS的開發中,就是一堆的MVC與MVC的互動。例如行事曆點選了Year View的某月後,會進入Month View,而點選其中某一天,會進入Day View…。Year View其實就是由一組Year的MVC組成,而Month View也是由一組Month MVC組成,以此類推會有Day的MVC,甚至填寫新事件頁面的MVC。因此以上的流程轉換,就是前面所稱的「一堆的MVC與MVC的互動」

在iOS 5之前並無Storyboard設計方式,需在獨立的.xib檔中設計View的UI,不同組MVC之間的流程,很難直接看的出來,只能從code中去了解。但自從有了Storyboard後,MVC之間的流程化被具象化出來,就像是分鏡圖一樣,可以從Storyboard中一眼就把整個流程架構看完,無論是拿來與相關人員討論或事後維護都非常的有幫助。更別說再更早期UI的開發要在另一套Interface Builder (IB)設計UI,再和程式碼整合的困難了。

基本上,iOS的MVC中,和其他程式相比差異最小的就是Model的部份,但在程式碼上許多初學者會一不小心,就把程式邏輯直接寫在Controller裡面了,造成了MVC只剩下VC。(其他語言亦然)

因此在程式碼的結構上,要養成好的習慣將Model的部份另外抽離出來,如此在被Controller呼叫時才可做到較有彈性與擴充性的設計。


Objective-C初探

我們常說.h檔是定義檔,.m檔是實作檔。Hegarty教授給了一個更實務的說法,.h檔其實就是你的API (開放出來讓人看的規格),而.m檔就是你不讓別人看見,以及其他所有要實作的程式碼。

所以呢,和Java或.Net這類語言不同之處是,我們並沒有針對各個屬性或方法設定所謂的「存取範圍」,也就是沒有什麼private、public…這種東西,反正你放在.h的,就是public,其他的就放.m就是了。

在View去拉IBOutlet和IBAction時,我們常有一種認知,覺得從UI元件按cmd接出的那條連接線就是要拉到.h檔的慣性,其實若你不是要開放出來的方法或屬性,其實拉到.m檔就好了,我之前真的是沒想過呢。

小地方注意:

  • @interface其實指的是在.h檔的class,並非其他語言的interface(在iOS反而叫protocol)
  • 在.h檔要寫繼承的類別,在.m檔則不要
  • 以@property來存取變數

Strong vs Weak Pointer

ex.
@property (strong, nonatomic) NSString *content;

在設定@property時,有個屬性要嘛就strong,要嘛就weak,但到底什麼是strong和weak pointer?

strong pointer是一種reference counting技術,只要所有被設定strong property所指到的物件(置於heap中),有至少一個以上還指著,那該物件就不會被回收。直到最後一個strong指標刪除,則iOS會自動釋放掉該物件的資源。但是這種自動的reference counting技術,在iOS 5後出現,正確名稱為ARC(Automatic Reference Counting),並不是我們在其他語言所說的GC(Garbage Collector)。

而weak pointer指的是,若此指標指到在heap中的那個物件,只要有超過一個strong pointer指向他,則幫我連接著;但若沒有任何的strong pointer指向該物件了(該物件會被釋放),則此weak pointer會一併被設定成nil。

strong和weak指標往往在很多書和文件上都說的不清不楚,大部份的人也都一知半解,說穿了就是亂用一通,反正好像run起來沒有很明顯的說出哪裡有問題,就這樣隨心所欲使用,哪一天出現了 memory的錯誤時,會非常難抓bug。


@property與@synthesize的改變(變得更省事了)

在iOS 5以前(換種說法,是在Xcode 4.4之前的版本),在.h檔設定了@property後,需要在.m檔加上對應的@synthesize,在.m檔中才可以使用self.的方式取用或設定property的值,或者重新覆寫getter或setter。


Emp.h中
@interface Emp : NSObject

@property (strong, nonatomic) NSString *name;

@end

Emp.m中
#import "Emp.h"

@implementation Emp

@synthesize name = _name; //這行

@end


但在iOS 6開始,在.h檔宣告了@property後,在.m檔已不需要再自行加入@synthesize,這些會由compiler幫我們自動加入(除了@synthesize語句外,也會幫我們自動加入預設的setter與getter內容)。

甚至我們要針對setter或getter重新改寫,也可以直接寫上改寫部份,也不會有問題。


@property的setter或getter的名稱變更

在Objective-C的property的setter與getter,和Java體系不一樣的一點是在於getter會與property名稱一致,前置詞不加上「get」字樣。setter則與Java相同。

也就是說,若你的property為name,則setter會叫"setName",而getter會叫"name"。

當然,若我們使用self.方式取用或設值,是不受影響直接都用self.name。但若是透過message傳遞時,就會使用原本message名稱。若有時候,我們有需要改變getter(或setter)的名稱時,讓程式閱讀上更清楚意思,我們則可在宣告@property時,直接做指定。

這種情況通常會發生在BOOL的property上,例如有個BOOL的property名稱為active。照預設,其setter會叫setActive,getter會叫active。但在Java中,我們通常會以較為符合英文文意的方式來看待布林值的結果,通常會以「is」作為前置詞,例如「isActive」。既清楚又好懂。

所以我們在Objective-C中也想要這樣使用的話,就是直接在@property宣告時指定名稱變更。

@property (nonatomic, getter = isActive) BOOL active;

這樣我們就輕鬆改變了一個較容易理解的getter名稱了!這種作法一般實務上,較常運用在BOOL的getter上,當然有時候也有其他的時機,是為了解決一些奇奇怪怪的問題時,也可以使用這個方法來調開名稱的衝突。(我之前開發的專案有遇到過,但我現在想不起來時機是什麼了)

2014年1月2日 星期四

來吧!成為史丹佛CS夜間部學生!

不得不為iTunesU歡呼一下!



當然最早推行開發式課程的MIT功不可沒,不過藉由iTunesU的資源整合,可更全面的搜尋與掌握更多精彩絕倫的課程。

其中課程排行榜居高不下,且課程不斷更新的當然首推史丹佛的iOS開發課程(Developing iOS 7 Apps for iPhone and iPad [CS193P]),由思路、技術與經驗超級豐富的Paul Hegarty講師主講。從之前幾年前開始的幾個版本開始我就看過了這個課程,但一直看個前幾課就停滯不前了。

Paul Hegarty的學經歷資料很難查的到,就我從各方網路資源查到的,他畢業於Stanford,畢業後進入NeXT工作,並且在矽谷創立了自己的公司。(資料實在不多)

直到最近出了iOS 7最新版本的課程,想想是時候該好好來看一看這門非常精彩又讓人獲益良多的課,除此之外,倒不如邊看邊做個筆記,把最精華的部份咀嚼吸收後,再轉化成為自己融會貫通的筆記,也可造福人群。


這個CS193P課程,雖然為全英文,但由Paul Hegarty精彩的講解,要不懂實在也很難。尤其他的投影片實在做的太出色了,這大概是我這輩子看過最清楚易懂的教學資源了。

不得不感嘆的是,史丹佛大學的課程也太精實了吧,這樣的課程若是用功一點的學生整套學完,真的直接上戰場沒問題呀!但也感謝有這樣完全免費佛心來的開放式課程,讓遠在台灣的我們可以直接學習到世界頂尖學校的課程,太感動了。

好吧,就利用下班的時間,把自己當成「史丹佛夜間部的學生」好好的上課吧!




iTunesU Link:
https://itunes.apple.com/us/course/developing-ios-7-apps-for/id733644550

CS193P Course WebPage by Paul Hegarty:
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/


2013年12月10日 星期二

設定VoiceOver的語音提示

有些用戶可能是視覺障礙或其他特殊用途,iOS以相當簡單的方式設定,就能完成輔助使用的目的。



當我們選定某個元件,例如UITextField,則在Identity Inspector (位在Utility區的左3)中,在Accessibility的Hint中輸入欲語音提示的文字內容,使用者若是有開啟了VoiceOver的輔助功能,則會聽到語言唸出我們輸入的文字囉!

預設Accessibility的Enabled是啟用的,因此我們不需要花太多的功夫,就可以讓我們的App支援輔助使用功能了。


2013年12月7日 星期六

iOS 7 API新玩意兒

在iOS 7 API中,有些可能是改良的功能或差異,在此篇中做紀錄,會持續update。

Header File Import之差異
    #import <foundation/foundation.h>
    
    //iOS 7中可改為:
    @import Foundation;  
    
    //注意是將#改為@,且後面多了分號。
此新的@import作法,又稱作「模組(Modules)」或「語意匯入(Semantic Import)」,僅可用於Import Apple官方Framework或Library。無法使用在使用者自行開發或第三方開發的類別庫。

其中有個優點是,透過這個作法,在code-completion (可按ESC)中會出現所有你可以用到的提示。舊有的#import作法,你必須知道完整的套件類別字串名稱,才可正確import。

其中,使用@import作法,在引入的效能上會比#import還要快速。還有一項特點是,透過@import的方式,可直接使用framework,不需要在Xcode Target Settings中的「Linked Frameworks and Libraries」中先行加入,他會自行引入你所@import的類別庫。


[參考] StackOverflow神解答:http://stackoverflow.com/questions/18947516/import-vs-import-ios-7


2013年12月6日 星期五

開發iOS App前需要了解的事。

這裡不寫最細節的內容,因為這些東西在Apple Developer網站上,寫的絕對比我詳細,內容也保證比這裡豐富,既然這裡是blog而不是白皮書,我就以指引方向為前提來寫。

首先,若你想開發iOS App,那麼你就不要想「省錢」這件事,這只會搞得自己很麻煩而已。蘋果的世界裡,沒有什麼事是不麻煩的,尤其當你從一個「使用者」要變成「開發者」時,這點認知一定要有的。


需要什麼硬體?

你要開發之前,總要有開發環境,因此你需要一台可以跑Mac OS X的電腦。你可以買最便宜的Mac Mini,也可以買Macbook,這端看你的需求而定。不要去想用PC來裝Mac OS X這件事,效能既不好,還會有一堆的限制,工欲善其事,必先利其器,這點錢就別省了,既然都立誓要進入Apple的世界了,有一台Mac是很合理也很合邏輯的。

接下來,就是你需要一台可以測iOS的硬體了。你可以買iPad,然後在上面跑iPhone大小的App。這是省錢的方案,當然如果你會有需要用程式去抓3G的一些設定,就買3G+Wifi版的,如果沒有的話單純的Wifi版就可以應付多數情況了。

用模擬器來寫App的話嘛,個人是不建議,因為畢竟App是徒手要在上面滑來滑去的,手感手順很重要,若你這點錢也要省,單純只想用模擬器來寫,我個人覺得使用者經驗這部份沒有辦法做的太好。當然你能有一台iPhone和iPad,是最完美的,若沒有,至少要有一台iPad Wifi版。

順便一提的是,最好是買有Retina的iPad (也就是iPad 2及以前,並不建議),畢竟你若要做HD版的,一定要在上面跑過才可以最精確了解每一個pixel的表現是不是如你預期。

(幫你找了很多理由和藉口來買Mac和iOS裝置了吧!)


需要什麼軟體?

若你是第一次接觸Apple的開發,你應該還不知道Apple在「這個綁那個,那個又限制這個」是有多麻煩的事吧。首先,你的Mac上面灌了Mac OS X,不是這樣就了事了,版本是很關鍵的事。版本不對,後面什麼都不對了。

目前(2013/12月)最新的版本是Marvericks (10.9),你的Mac只要夠新(約4~5年左右的Mac),基本上就能安裝。這個版本會決定你的開發IDE Xcode可以裝到多新的版本。

Xcode是用來開發iOS App的IDE開發工具,他也有一個版本,你要安裝愈新的Xcode,才可以開發愈新的iOS版本App,而你要裝愈新版的Xcode,你本身的Mac OS X也要夠新才行。這就是我上面說的「這個綁那個,那個又限制這個」。寫到這裡,不知你頭腦打結了嗎?

舉個實例好了,如果你想要寫的是iOS 7的App,你就至少要將Xcode升到5.0以上的版本(安裝iOS 7 SDK),且你的Mac OS X至少要10.8.4以上版本才可安裝該版Xcode。

接下來就是,iOS本身也有一個版本。這個版本呢,也很重要,如果你的開發用iOS裝置想要保持在某個版本上(例如iOS 6),那麼請不要輕易的升級。
若你原本是採用Xcode 4.5在寫iOS 6的App,用了一台iPhone 5安裝了iOS 6,運作的很好,有一天你突然把你的iPhone升到iOS 7,不好意思,你的Xcode會跟你說你的iPhone裝的版本太新了,他不能支援,你就必需升Xcode,然後可能此時又發現Mac OS X又不支援,也要升級,就會出現一關卡一關的冏境了。

等你都升好了以後,發現你原本Xcode可以讓iOS 5的人安裝,現在新版Xcode升級後,最低變成只能開發在iOS 6.0以上執行。

你只不過是不小心升級了你開發用的iPhone的iOS版本,就會不小心出現大災難,身為Apple開發者,我相信你會很懷念以前傻傻的當使用者的時光。(而且那時你也罵了Apple說很機車,這時才發現,身為開發者才該罵吧!)


決定你的開發者Program

如果你都了解上述的卡關限制後,還打不倒你,你就可以開始進入開發者的世界了(其實後面麻煩的事更多)。

首先,請先到Apple Developer網站逛一逛,了解一下你未來的家(誤)。

https://developer.apple.com/



當你要成為Apple開發者,你要先了解你需要申請的是哪一種Program。
基本上目前分為三種Program:
  1. iOS Developer Program (含個人與組織)
  2. iOS Developer Enterprise Program (企業內部專用)
  3. iOS Developer University Program (大學教學目的)
https://developer.apple.com/programs/start/ios/

基本上上面這個網址就講的很清楚了,不過有人搞不懂「我是一個公司,到底要申請第一種還是第二種」。

第一和第二種簡單的區別是,第一種是要上架到App Store的,所有人都可以下載的到。而第二種主要用於大型企業,開發的App是不上架到App Store,而是放置在公司內部自行架設的伺服器上安裝使用。

如果我記得沒錯,以前第一種是區分成「個人」與「公司(Company)」兩種Program,但現在已經整合了。只是差在若你是以公司組織單位要申請,一定要提出D-U-N-S碼相關文件,這個以我之前的例子:要審非常久!而且申請文件千萬不要有錯,不然重跑流程非常花時間。


一般人較少有機會接觸到Enterprise的Program(多半都是第一種),因為工作上我主要開發的就是Enterprise Program,若有機會我再與大家分享這方面的相關經驗和資訊。


在Developer網站上,其實有非常多的資源,只要你願意看(英文),基本上上面夠你看很久很久了。但是要跟大家說明一下,就是Apple Developer實在太常改版了,尤其是「Certificates, Identifiers & Profiles」專區,這個日後再提,不過很麻煩的是每次卡完了圖,過沒多久版面又改掉了,常常會造成講的地方跟最後改版的位置或功能名稱不相同,實在有點擾民就是了。

這篇就介紹到此,有興趣的人請自行研究囉。


2013年12月5日 星期四

網誌前言

開一個網誌前,不免俗要自我介紹一下,不然你們在看誰寫的文章都不知道,就照單全收好像也挺冒險的。

Who am I and why do I create this blog?

我的大學與研究所唸的都是資訊管理,在資訊領域界中打滾了差不多八、九個年頭了,自從Google發明了大神搜尋系統後,這一路上,從網路中許多神人的經驗分享幫助下,讓自己也能這樣跌跌撞撞在資訊領域存活了下來。

從最早學生時代寫ASP網頁,碩士延畢了一年,在家兄的新創網路公司中開發了PHP網站與Web3D程式,曾經從無到有企劃與開發3D換裝系統虛擬社群網站,玩過了挺少人在接觸的Quest3D虛擬實境系統。

接著四年的國防訓儲生涯,在航太產業開發各種網站與軟體,使用了Java、JSP、Spring MVC、Perl、C# .Net、SAP、Spinfire相關技術,發展了一套給公司工程設計部門使用的web-based VPM,用來管理Catia的各種3D零件組裝檔案。中間過程中,為了精進自己的程式與伺服器管理技能,考了SCJP和RECH證照。

國防役結束後,短暫到了澳洲打工度假(度假是實,打工是虛)幾個月後,回台灣又再度進入家兄的公司,這次經過了航太產業四年的洗禮後,技術能力提升了之外,從工程單位又回到了3D網頁多媒體的產業。

在這一年內,一個人當好幾個人用,開發的方向非常多元,參與開發了幾個新穎的標案計劃,主要發展3D Real Time的應用程式(Unity3D x C#)、也接觸了AR(擴增實境)和用Flash ActionScript寫3D多媒體系統,重回PHP領域外加Smarty、JQuery與ExtJS,做了一些建築產業的東西,購物,旅行業,鞋業,學術單位,各種領域應有盡有。

這一年相當充實,但階段性任務告一段落後,隨後進入了光電產業發展。

這也是目前的工作,這份工作內容和第一份在航太產業工程單位其實挺類似的,目前的工作主要使用ASP.NET(VB),開發各種企業內部用途的網站與單機程式,近兩年因為要發展雲端與Mobile,因此也順勢進入了行動裝置的開發行列,除了碰過一些Android之外,主要開發的都是iOS的App(我有幸能玩到一般較少人會接觸的Enterprise Program)。

除了程式的開發外,因為公司導入了CMMI Level 3,而且我參與的系統多半與整合CMMI流程有相關,因此也讓自己對軟體發展流程有更精實的認知,不過開發系統的彈性和速度,往往會跟嚴格的開發流程之間是天秤的兩端,總不能又要輕巧又要快,但又要每個流程環結都能的完美無缺,這實在是一個Trade-off。因此中間過程中,也參與了實驗性的SCRUM的敏捷式開發。


那所以呢?

聽了以上這些,這也不是在寫自傳,總之,這些年下來,發現自己接觸的面向相當廣泛,各式各樣五花八門都略懂略懂。

因此,自己意識到這樣發散下去好像無法聚焦,是到了該收斂的時候了。

於是挑了這兩年來主要開發的iOS來做為技術專精的目標。這個網誌也是為了這個而存在的,尤其是年紀也有了,記憶力衰退的同時,更需要找個辦法將自己辛苦研究的東西做個保存,以防日後自己需要再研究時也較為方便,同時又能造福人群。

當然,以目前收斂的速度來看,我寫的東西主要會是偏向給新手讀者指引用的,要再深入的話可能還需要一點時間。

往往自己遇到一些問題時,都是在StackOverflow這個神人出沒的地方找到解答,但我知道許多台灣朋友都有「看英文不耐症」,往往錯過了很多精彩的神解法,實在很可惜。這方面我也會著手做些零碎的紀錄,將自己所碰到的問題以及可能四處向洋人取經求得的解答與大家分享,讓更多的人不需要再走一樣的冤枉路呀。


寫些什麼?

那麼哪些是我會寫的,哪些又不寫呢?我曾經想過要效法Linux第一把交椅鳥哥一樣來寫文章,但發現Linux是歷久彌新的系統,有很多觀念都是可以貫穿古今。但iOS發展與變化有點過於快速,如果我也來從頭開始當教學筆記這樣寫,等寫完第1章,大概iOS也從7升到9了吧?而且可能寫的東西也不一定適用,時效性實在太低。況且這方面的基礎細節教學,就目前的iOS資源來看,已經有相當多且完整了,大家直接善用那些資源其實更為有效率。

因此我還是調整一下方向,是以不連慣單元,但採分類方式來紀錄(這也是一般網誌的型態),但記得東西都是我個人覺得值得分享的內容,值得分享的有可能是很基礎的,也可能是較少人在碰的,也可能是我剛好開發的案子有遇上的,這樣既有效益,也較無壓力。


如果你也準備好了要一起踏入iOS的開發行列,就讓我們一起互相幫助一起成長吧!