2014年12月30日 星期二

Effective Objective-C 讀書會 第2篇

範圍

主題06:瞭解特性
主題07:從內部存取實例變數時,主要採用直接存取的方式
主題14:瞭解什麼是類別物件
主題18:優先採用不可變物件
主題27:使用類別延續類目隱藏實作細節

整理

主題06

一、Property 是什麼?

特性 (property),嗯…我完全不喜歡書中的解釋,也不喜歡「特性」這個中譯名。很不明確,所以筆者要引 OMG UML-Superstructure-formal 的定義:

7.3.45 Property (from Kernel, AssociationClasses, Interfaces)
A property is a structural feature.
A property related to a classifier by ownedAttribute represents an attribute, and it may also represent an association end. It relates an instance of the class to a value or collection of values of the type of the attribute. 
這裡說明了: property 是一種結構特徵。也就是說,它不是一種特例於某個語言的功能。若把類別一分為二:不是資料(或稱「attribue」、「成員變數」),就是行為(或稱「method」或「成員函式」)。沒有別的東西了。那 property 是什麼呢?

簡單講,property 是 attribute 的 subset。但是它不同於一般的 attribute,是因為它還具備有表示
association end 的職責。換句話說,property 是具備與其他類別建立關係的 attribute。這表示它有公開的性質。

在 Java 來說,宣告一個 private attribute 後,建立相對應的 getter/setter methods 就是讓該 attribute 變成一個 property 的例子。而 Objective-C 則是例用 @property 這個關鍵字讓 compiler 知道:這個 attribute 應該有對應的 getter/setter 實作。

所以對於 client end 來說,可以在得到某 instance 後,利用該 instance 提供的 getter/setter methods 對該 instance 所對應的類別中有定義的 attribute 進行存取。

在之前,我們還得在實作程式碼(.m檔)中以 @synthesize 將 attribute 與 property name 進行配對,這樣 compiler 才會在編譯階段把 getter/setter 加入至實作程式碼中。以現今的時間點,相信 synthesize 快被大家遺忘了…。

二、存取 Property 語法:用點號

「點號語法 (dot syntax)」是另一項專屬 property 的語法,背後只是代為呼叫該 property 對應的 getter/setter methods。可以不自己寫 getter/setter methods 及可以使用點號語法,說實在,真的是一個很省時間、很簡潔程式碼的作法。 Java 為何不引入這種語法糖呢…?

三、 Property attributes

好,問題來了:

  1. 如果我們只需要唯讀的 property 怎麼辦?也就是說,只想提供 getter method,但是不提供 setter method,做得到嗎?要怎麼告知 compiler 這項需求?
  2. 我們可以對 setter method 做進一步的控制嗎?根據我們對 heap 內物件保存方式的認知,我們可以在 setter method 內對傳入參數做進一步加工,例如 retain 它,那使用自動生成 setter method 時,該怎麼告知 compiler 這項需求?
  3. 我們可以撰寫自訂名稱的 getter/setter methods 嗎?

以上答案的解答,只在於:宣告 property 時,給予合適的設定即可。這裡用「設定」代稱「Property attribute」是由於不想和 object attribute 混淆。

書中分四類,我分三類:

  1. 和執行緒安全有關:nonatomic 及 atomic。一般用 nonatomic。為什麼?效能問題,而且使用良好的 GCD 操作取代對 NSThread 的控制,就大半可以不用擔心執行緒問題。
  2. 和 getter / setter methods 的生成有關:readwrite (預設值)、readonly(只生成 getter method)、getter= (getter method 的命名)、setter= (setter method 的命名)。
  3. 和記憶體管理「語義」有關:
    1. assign 和 weak :兩者作用類似,但 assign 用在數量型別、weak 用在物件。明顯和 stack /heap 的設計原理有關。
    2. strong:和過去 MRD 時代的 retain 為相同語義。
    3. copy:和 strong 不同的是,它不 retain 物件,而是複製出一份自己用的複本。
    4. unsafe_unretained:在下一回的讀書會中,會有更進一步的討論。

四、非脆弱的ABI (Application Binary Interface)

這裡強調非脆弱的 ABI 讓 Objective-C 能夠在「如果類別定義發生改變,儲存在類別物件的偏移量會被更新」,因此能解決執行期由新類別定義導致的不兼容問題。而克服直接讀取實例變數可能造成偏移量偏差的方法之一,就是使用 property 提供的 getter / setter methods。

主題07

這個主題延伸了主題06對於  Property 的討論。作者強烈地建議:
在內部直接存取實例變數,但是用 Property來設定實例變數。
為什麼呢要直接存取實例變數?

  1. 會比較快,因為不必透過 method dispatch 機制。
  2. 不會觸發 KVO 機制。作者是這麼說的,但是和我的實作不合。直接 assign 給實例變數還是會觸發 KVO 機制。更具體地說,使用 addObserver:forKeyPath:options:context 進行監控的實例變數,還是會觸發 observeValueForKeyPath:ofObject:change:context 方法。

為什麼呢要用 Property來設定實例變數?

  1. 可以遵循由 property attribute 所規範的記憶體管理語義。
  2. 偵錯容易,因為我們可以在 getter / setter methods 裡設定中斷點。
不過這個建議不是哪裡都可以用的。因為:
  1. 由於子類別可以 override 父類別的 getter / setter methods,所以若在 init method 中使用 getter / setter 則可能在子類別建立時發生意想不到的錯誤。
  2. 也有相反的情形:我們必須在 init method 中使用 setter method,因為該實例變數是繼承來的,不透過 setter method 根本存取不到。
  3. 若希望運用 lazy initialization 機制:除非真的用到,不然不產生實例,那麼就該使用 getter method 來進行存取。
聽起來這個建議的例子挺多的…,我覺得可以當成是重構時的思考項,在程式碼初生的階段,可能不用想這麼多。


主題14

大概物件導向語言都有個重要但是卻不常被提及的物件,那就是「類別物件」。我喜歡用 ActiveRecord 的設計語義來詮釋類別與物件:類別是專有名稱,是唯一的;物件是普通名稱,是可數的。

在有 namespace 或 package 結構的程式語言中,類別全名指的是包含該 namespace 或 package 的名稱。例如:在 Java 中,String 類別的全名為「java.lang.String」。而對於 Objective-C 來說則沒有 namespace / package 的部分。就像在 Java 世界不會有第二個 java.lang.String 類別,在 Objective-C 來說,也只有一個 NSString 類別。(正常的情況下)

當程式試圖利用一個類別、生成該類別的實體(物件)時,會先截入該類別至記憶體、生成類別物件,此物件為 singleton object,然後才是以該類別物件做為模子生成對應該類別的物件。

Objective-C  的每個物件的「第一個成員」,被規範為一個用來定義物件自己所屬類別為何的變數。這個變數為「is a (是)」指標。可以觀察一下最基礎的 Class 類別的定義:objc-class.h

在 Objective-C 的 Foundation 框架利用 Class 類別定義中的 「is-a 」指標,在執行期能進行物件型別的檢查,使得 NSObject 物件都能使用所謂的「內省 (introspection)」機制。說穿了,就是在執行期進一步確認某物件的確實類別、實作了哪些方法的判斷機制。

所謂的內省機制,至少包括了兩項方法:isMemberOfClass 及 isKindOfClass。

  1. isMemberOfClass:判斷某物件是否為特定類別的實體。
  2. isKindOfClass:判斷某物件是否為特定類別或其子類別的實體。

這兩個方尤其常用在從 collection 物件中取得單一 element 時。為什麼?來看看 NSArray 及 NSMutableArray 中的方法定義:

  1. - (id)objectAtIndex:(NSUInteger)index;  //NSArray.h
  2. - (void)addObject:(id)anObject; //NSMutableArray

由上述兩個方法得知,自 collections 物件中取出的 element 或要存入的 element 並沒有限定為特定類別的實體。和 Java 5 以後版本比較起來,少了「泛型」語法。在 Java 中,會這樣產生一個「只能由 String 實體為 element 的 List 物件」:
List<string> aList = new ArrayList<string>();
而對於 NSArray 來說,它可以裝載的 element 並不限任何型態,可以說很自由,但是更容易造成混亂(至少提供了造成混亂的空間)。所以在從 NSArray 中取出 element 或設值/插入值時,會比較頻繁地使用 isMemberOfClass 或 isKindOfClass 這兩個內省機制中的方法。


主題18

這個主題的標題是「優先採用不可變物件」。老實說,這應該是個錯誤比大於正確比的標題。因為看到這個標題時,我預設會看到例如 NSString 與 NSMutableString 之類的字眼,但是並沒有。在看過通篇文章後,我覺得標題應該區分為兩個:

  1. 留意物件的可變性是否合理。
  2. 使用 collection 物件時,要留意裡面 element 的可變性。
以書中例子所言,若有個功能近似 DTO (Data Transfer Object) 的物件,此物件的 data source 是來自某 Web Service,那麼由於不會有「回傳改變後的值」的需求,所以該物件的可變性是不合理的。

這種情形下,作者建議使用 property attribute 對該物件加以控制。也就是說,把該物件納入 property 的一員,並使用 readonly 的 property attribute 對其加以約束即可。

此外,假若 property 為 collection 類別時,要留意:我們可以讓 collection 保有的 element 是固定的,但是那不表示 element 的內含值是不可變的。即便如此,也不表示我們必須針對每個 element 的存取以內省機制加以檢查。作者說:
…不要透過內省機制檢視回轉給你的任何物件而判斷它是否可變…你應該不惜代價避免那樣做(不應該使用這樣的內省技術)…

說到底, collection 中的 element 是否可變,端視加入的 element 本身的可變性。而是否加入具有可變性的 element 的判斷,應該由程式的使用方明確表達其意圖,而非由 API 的提供方預設立場地加以限制。更何況,還有其他的技術可以繞過這樣內省技術的檢查,終究是無法完整防禦的。

這個主題的範例最過癮的地方在於示範了類目延續類目 (class-continuation category)如何覆寫 @interface 區段的 property 宣告設定。

類目延續類目…這個名字有夠爛,我接下來只稱呼它:寫在實作檔中的「暱名 category」。

在 @interface 宣告區動段,我們可以宣告某 property 為 readonly,然後在實作檔中的暱名 category 區段再一次宣它它為 readwrite,這樣的話 Runtime Library 還是會替該 property 建立 setter method,只是除了類別本身實作檔外,其他外部類別的物件是無法讀寫該 property 的。

是嗎?不是…其實透過 KVO 機制,Runtime Library 還是可以幫你找到那個實際上有實作的 setter ,然後使用它。所以…只能說使用暱名 category 的方法很不錯,但是也不是完美的。

主題27

其實在上一個主題已經提及了這個主題的主角:類目延續類目 (class-continuation category)。好吧,再說一次:我接下來只稱呼它:寫在實作檔中的「暱名 category」。

簡單講,我們可以把不想寫在公開介面 (.h 檔)上的任何資訊寫在這個暱名 category 中。

這點對於一般程式開發來說,其實不算是非常必要的觀念,但是對於 API 開發者來說,盡可能透露出最少的訊息給外界使用者是極為重要的。因為曝露在公開介面的資訊是不可以隨便修改及移除的,任意地修改將為 API 既有使用者不必要的困擾。

所以不論是有不需要公開的:

  • protocol
  • IBOutlet
  • IBAction
  • method
  • attribute
  • property
都可以寫在暱名 category 中。事實上,以往在 Xcode 中開啟 Assistant Editor 時,會開啟對應 IB 上選取中 ViewController 的 .h 檔,而在 Xcode 5 版後就預設改成開啟 .m 檔,而非 .h,就是這個考量。

使用暱名 category 的另一個好處是可以比較好搭配 Objective-C++程式碼。這部分我完全不在乎,所以不在此討論。時間好少,有更重要的書要念、有更切實際的文章要寫。


2014年12月23日 星期二

《我跟賈伯斯學到的40堂超強工作術》讀後整理

書名:我跟賈伯斯學到的40堂超強工作術
作者:山元賢治 (2004年認識了賈伯斯,成為Apple日本分公司社長)
原書名:「これからの世界」で働く君たちへ

對於書名的,筆者覺得有點什麼了點。原文書名若直譯為中文,大概是「給要在以後的世界工作的你們」,基本上沒有賈伯斯的名字,也沒有強調什麼超強工作術。作者的確當過 Apple 日本分公司的社長,當然也認識賈伯斯,也從他身上學到了不少;不過,作者的經歷也包括 IBM、Oracle 、EMC,內容中他也從這些各別不同公司的文化或人物裡學到了不少事物。所以這個書名,還是覺得有點太耍花招了。覺得原書名就很有誠意了。

這本書強調了不少重複於其他書中會有的概念,不過若加上作者的實際人生作為印證,則多多少少強化了訊息的可靠度及重要性。作者目前還開設了「山元塾」,用以作育能在未來以全世界為基本平台當目標的人才,而這本書,事實上就是出元塾的課程內容加以整理後的作品,雖然並沒有銀彈,但是反複地看類似的書,筆者還是覺得需要的。畢竟出了社會後,自己必須成為自己的老師,而這位老師也需要時時提醒自己的。提醒的方式,就是多多去經歷、閱讀、反思及行動。

整理如下:

一、健康的身體

這裡的「健康」是指充沛體力及易於達成目標的生活作息。試想,要成為以全世界為平台的人,會遇到什麼事?首先,會遇到很多人,隨之而來的是很多的溝通場合;得到達很多地方,要有能適應時差的能力;當然也會有不少會議、不少需要反思進行的決策、很多要睜開五感去學習的人事物。如果有沒相當的體力,是完成不了上述工作的。

書中提到:「體力就是一切的基石。沒有體力,我們甚至無法樂觀地看待人生。」,如果讀者也有一定的工作經驗及年紀的話,看到這句話應該也多有感觸。

在書中以目前 Apple CEO 提姆.庫克為例:「他每天早上都會去健身房運動,一大早就開始跑步、騎腳踏中及舉啞鈴…這樣的生活和工作方式,讓人覺得神清氣爽。」而且這樣的早晨型態並不是 Apple CEO 的特權、個人嗜好,而是作者認識的多數一流商務人士的共同生活模式。

此外,作者也斷言:「沒有領導者是夜貓子」。他提倡的是「早一小時起床,多累積一點實力」。這個論點也好多次被各類工作術相關的書籍所提及過了。原因很簡單:運用早晨人腦集中力最好、思路最敏捷、雜念最少的時刻、有效率地完成對自己而已最重要的事,然後日積月累,就得以收獲。這樣正面能量的正面循環,正是一種使成功變得比較容易的祕訣。

二、好奇心

當我們擁有健康的身體、充沛的精神後,才能回到我們原始的狀態:一種接近童稚的情懷。我指的是:對任何事情具備十足的好奇心、能即刻以行動滿足我們的好奇心,而且毫無保留地接受結果、收接結果。

在本書中提及「領導者一定具備超級強烈的好奇心」,而我認為:好奇心是人的天賦之一,但是若我們沒有健康的身體、充沛的精神,而是被生活中許許多多不懂割捨的煩人小事所累,那麼好奇心自然會關閉。就像靈魂不再自由,活在自己建造好的堅固地生活牢籠中。

光是還原到擁有好奇心還是不足夠的。必須要有的是敏銳的觀察及理解,並且能提出直擊核心的問題。這樣的問題所承載的好奇心更具強烈的意圖,也才能是推進一切的動力來源。

擁有強烈的好奇心後,還得知道:好奇心的答案往往可以成為更多好奇心的起源。正應如此,這樣的循環自然追求的是更好的問題及解答,永無終止的一天。

書上說:「對新產品的滿意度,只維持到上市的下一秒。」

此外,好奇心能增加工作效率。作者在第15篇的標題提到:「做一件事,至少要問七個為什麼」。「工作上最重要的技能,就是『提問力』」。能夠問對問題,才能得到好的解答。而這個提問的源頭,和強烈的好奇心息息相關。

三、熱情

若說好奇心是天賦,熱情則比較接近是後天人格特質造就而成的。作者說:「世界上最強的武器,就是『熱情』」。

與熱情直接相關的,我認為是價值觀、是自我的人生故事,也是一種感動的傳遞。通常熱情不會憑空而來,這點和好奇心不同,熱情植基於對某特定價值的肯定與深掘,而那背後應該存在著一個讓自己感動的故事。由於想傳遞那樣的感動以予別人,所以我們會披星戴月去窮究、去創造及滿足我們的好奇心。所以熱情說來是一種過程的展現,而非一時的激情,這點總是容易被人誤會。

如果有誰認為自己不知道自己的熱情在於何處?所要為何?那大致源於缺欠自我的深掘。就像書中賈伯斯曾說過的那句話一樣:「You should all know already」。所謂「缺欠自我的深掘」說起來好像是自己努力不夠一樣,這點筆者也覺得:的確有些人比較幸運,在人生很早的階段就能知道自己的未來將要是什麼,也知道要到達彼岸該怎麼規劃、也擁有一定的資源及支援。不過,即使沒有那樣的幸運,在尋找自己熱情時也可能遭遇到一些危險及苦痛,但是總比就這樣放棄的好。筆者深深地這麼覺得。

四、時間管理

人生公平的事情不多,大概只有兩件:第一,每個人一天都只有24小時;第二,每個人都會死。

既然每天要投入在工作的時間超過與家人、朋友、寵物相處時間的總合,那麼好的時間管理,就是好的工作管理,甚至就是好的人生管理。

管理二字,我們拆開來看:「管」就是「管控」,筆者認為就是挑選自己要去做的事,而不是一味地窮忙。我們的時間都一樣,誰做的事能更能聚焦在美好的事物上,誰就過得更快樂。這裡可以引入「80/20」法則,或是一般的時間管理矩陣來進行分析。「理」則是「整理」,整理包括「組合」、「排列」。簡單的一般說法是:把性質相同的工作在合適的時間及場合組合在一起完成;此外,任務的執行順序需要依重要性做妥善的優先性管理,重要的先做。

整理其實還包括另一個前提,就是:當事情一團亂時,是沒辦法整理的。必須要先 devide and conquer,也就是得先分化大問題成為合適的小問題。這一點是書上沒有提的,恐怕是被認為是早該知道的預先原則了吧。

「重要的」先做,這句話本身並不精確。有時我們要求的重要性是完整,有時則是速度。這個又再一次牽涉到價值觀或現實性問題。這時我們要保持對原有信念的追求,但也同時不斷地修正與煅化我們追求信念的方式及態度。

此外,人際關係的管理也屬於這個範疇:別浪費自己寶貴的時間在不重要的人身上。除非家人及朋友,不同類型的「導師」也是值得投資時間的對象。如何尋找這樣的「導師」,則有賴自己 open mind 及觀察、主動積極地與其建立關係。而且很幸運的,真正值得跟隨的「導師」通常也樂於分享自己的經驗、或是不保留不矯情地提出直接的建言。

五、站在用戶立場

據說賈伯斯在公司內很常講的一句話是:「我想做出連我母親都會使用的產品」。

所謂站在用戶的立場,我想不是無限上綱的「以客為尊」。而是以自己確信的方式、方向,努力將人類的生活變得更美好。這沒有一定的法則,若存在的話,今天每家公司應該都可以像蘋果一樣成功才對。所以,真正該如何「以客為尊」,也是必須探掘的。賈伯斯已經去另一個世界創造產品了,我們只能從他留下的正面元素(他也不是完人)去嚐試找出自己的信念、方向及步驟。

有個簡潔的重點思維可以作為我們去深掘的指南:製造產品或提供服務的公司及其員工,也必須能夠被自家產品/服務所「感動」才行。這點聽起來很簡單,但是其實因為組織上政治的隔閡或功能性上的分工,很容易弱化團體目標,使願景在一般員工心裡成為不可自求的目標。那樣的目標,會變成公司的目標,而與個人的目標產生差距、甚或毫無關係。這樣生產出來的產品、提供的服務,自然也無法感動用戶、無法產生驚豔的體用者體驗。

六、捨棄昨天的成功

個人或企業或多或少都會累積些成功的經驗,並以此建立行為模式或實體組織。在這個時候,其實當下的我們,並非正處於該模式或組織的初生起點,而是往往已經站在峰點上了。就像雲宵飛車靜止不動、準備在下一秒向下俯衝的位置一樣。換言之,不論之前經歷過什麼成功,在模式或組織被建立的同時,其生命週期就在往歸零的方向不斷邁進。於是模式成為習慣,這讓個人排斥新事物的衝擊、成為即將被汰換的人或是會驅逐良幣的劣幣;於是組織開始僵化、甚至泛政治化,成為不會跳舞的大象。

作者在第24篇的第一句話就是:「工作上唯一不變法則,就是『持續改變』」。

所以,我們應該週期性地思索過去、現在與未來自己的位置、定位及前進的方向及方法。不同範圍大小的週期適合不同主題的思考及檢討,注意觀察自己及他人的心態及反應,千萬別讓昨日的成功造成明天的失敗。

反過來說,樂觀看待失敗、從失敗中汲取寶貴的經驗則是趨近成功的登門階。不論是成功或失敗的經驗,都是一時的,也都是資料庫的寶貴的資源,絕對不該浪費。

七、減法思考

人總是直覺性地使用加法來解決問題,但是其實進入感性時代的現在,減法思考才是把事情做對、做好、讓用戶感到滿意甚或驚豔的訣竅。減法的目的是讓我們能更加的專注於最主要的客戶,試圖使用最少量的操作步驟、功能的組合來讓產品更好用、服務更便利。所以作者提及:「懂得『選擇和專注』,是讓蘋果贏得IT業龍頭的重要關鍵。」

這個道理說不定是多數組數最難得到的 DNA,是必須進一步研究檢討的。


延伸閱讀

《少了一部分,為什麼更值錢?》






2014年12月22日 星期一

Effective Objective-C 讀書會 第1篇

範圍

主題01:熟悉 Objective-C 的根源
主題11:理解 objc_msgSend 的角色
主題29:理解參考計數

整理

主題01

打開 Objective-C 的身份證一看,它出生自1983年,是受Smalltalk語言啟發並擴充標準 ANSI C語言而成的物件導向程式語言。它是商標權是 Apple 的,Apple 也是它的主要開發者,而 Apple 將它作為開發 OS X 與 iOS 相關應用程式的主要程式語言。

Apple 是 Objective-C 的實作者,不過設計者另有其人。查查維基百科後,發現設計者有兩位,生平事績不多的樣子,而且和 Apple 的淵源不太明顯。不曉得那兩位設計者現在會不會覺得受寵若驚,或是因此名利雙收?這些猜想都未經查證了。

Objective-C 的長相挺特別,有很多的「方括號」,方法名稱的長度被人誤稱為「冗長」。冗長的說法大概是對比於成名早於它的前輩程式碼語言,因為那些前輩很愛用縮寫,那些前輩的程式員簡直就當自己是魔法使,程式語言就是他們的咒語一樣難解、難記但是能讓電腦很酷地工作。比較起來,Objective-C冗長的方法名稱,造就了較佳的程式碼可讀性。假若大家同意:自己每天讀程式碼的時間都比寫程式碼的時間長,大概就會同意 Objective-C 的特性之一是「可讀性高」而不是「冗長」。

Objective-C 是怎麼把物件導向的特性加入至 C 語言中的?答案是:將 Smalltalk 的訊息傳遞機制導入 C 語言。這個答案成為主題01的重點。

messaging 架構和 function calling 架構差在哪?很簡單講就是:前者是在 runtime 階段決定執行內容,而後者則是在  compiler 階段就先決定好。由於一般高階程式語言都是:compile 階段
 -> linking 階段 -> runtime 階段的執行順序,所以可知:messaging 架構花在最後的 runtime 階段的執行成本高,而 function calling 架構則在 compile 階段就決定好,這樣每次執行的執行效能應該會比較好。

從可程式化的靈活性來看,由於 messaging 架構是到 runtime 階段才決定實際執行的內容,所以比這一點的話, messaging 架構的靈活度又高於 function calling 架構。也就是說,messaging 架構動態支援比較好。

Objective-C 的 messaging 架構主要是由 Objective-C 的 Runtime Library 實作。身為一般的開發者其實是用不太到 Runtime Library的,除非你正在為 Objective-C 實作 debugger 或跨語言的橋接。這是官方說法。

主題01的第二個重點,則是提到了和 C 語法在記憶體設計相關的機制。簡單講,程式語言在執行期會在主記憶體內規劃出三個區段用來運作語言本身。三個區段分別為 global、stack 及 heap。程序導向語言中的 global 變數或是物件導向語言中的類別屬性會放在 global,而生命週期有明確規範的資料結構會存在 stack,而物件會存放於 heap。

為什麼物件存放在 heap?因為它的生命週期無法用 scope 規範:物件可以在整個  App 裡被各種其他的物件參考,只有在它本身成為孤島或某一孤島的一員時,生命週期才會準備被結束 (還不是立即),所以不符合能放在 stack 的原則。這個其實想想 stack 的工作原理就能明白。


圖片來源:http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap


主題11

這個主題延伸了主題01中的 messaging 機制。
很簡單地講,就是當有一個式子如下:

id value = [someObject messageName: parameter];

而 compiler 會將其轉換成:

id value = object_msgSend(someObject, @selector(messageName:), parameter);

在 runtime 階段,Runtime Library 負責在 someObject 中找尋 messageName:,若找不到就往父物件去找,都找不到時,會引發 message forwarding 機制。找尋 messageName: 的過程會記錄在 someObject 對應的類別有含有的一份 fast map中做為快取,所以 messaging 其實也不會比 function calling 慢多少。

有關於 object_msgSend 相關函式還有很多相關的方法,要進一步鑽研,就得去看 Runtime Library了。


主題29

這個主題延伸自主題01中提到的:物件存放在 heap 區的觀念。

由於物件的生命週期是由還有多少其他的物件擁有/需要他來決定的,而不是由可結構化的程式區塊/scope決定,所以物件被放在 heap 區,而非 stack。而這個主題要回答的問題是:什麼時候在 heap 中的物件該是生?何時該被銷毀?

很簡單的說法是:當有人需要物件,它就因應而生;當再也沒有別的物件需要它時,它就等著被系統回收。(嚴格講起來要提一下 run loop,不過…先這樣理解吧)

Objective-C 用於管理 heap 中物件的方式,叫「參考計數」。想像每個物件身上掛著這個計數器,它一出生時,大抵上計數器上的值為「1」:因為產生該物件的物件將擁有該物件。

所謂的產生,大概說來是指使用 alloc 及 init 相關訊息來新創一個物件的行為。
然後當有別的物件也需要「他」時,可以向「他」傳遞 retain 訊息;反之,可以傳遞 release 訊息來表示不再需要他。

一旦「他」這個物件身上掛的計數器為0,他就會被系統標示成非使用中,然後等著被消滅。

這個機制有個簡單的原則:誰產生/擁有了某物件,就要負責釋放他。這個講來簡單,但是還是挺需要練習和思索的。

此外,還有以下注意事項:

  1. 一旦某物件的計數歸零,就會被標示為非使用中,但是其參考變數仍指向它,很可能造成不可預期又難以尋找的臭蟲。所以若確定 release 後計數應該歸零,最後在下一行緊接著把參考變數指向 nil 值。
  2. 設定  property 特性時,使用 retain / strong 的話,在 setter 執行時,其內容相等於:保留傳入參數、釋放原屬性,然後把傳入參數指派給原屬性。這個可延伸至主題06。
  3. 這個主題中,延伸了 autorelease 這個機制的討論。要很簡單的說,就是把 release 的時機延後到出了 autorelease pool 的範圍再說。這個可延伸至主題34。
  4. 這個主題中,還提到了物件的保留循環 (retain cycle)。有個更傳神的說法是「孤島效應 (island of isolation)」。簡單地說,就是有一組物件互相擁有/需要,但是他們和應用程式中的其他物件都沒有掛勾到,而自成了一個小圈圈。應用程式用不到它們,而它們的計數值也都不為零 (因為小圈圈內的物件互相需要),所以也不會被系統偵測為應該消毀的一群佔著記憶體不工作的物件小團體。這個可延伸至主題33討論。

延伸閱讀

  1. 維基百科 Objective-C
  2. Objective-C Runtime Reference

對於 Swift 語言一點想法

對於 Apple 今年發佈的 Swift 語言,在自己經過學習及試作的經驗之後,我發現自己目前還是不太了解:為什麼  Apple 需要發展這一套語言?

Apple 和生產產品、提供服務的企業都有著傾聽消費者心聲的共同理念。有為數不少的企業也只是口頭上講講,實際執行上總有無數種無奈、而不去切實地去執行該理念的業務理由;但是這樣的理念似乎是 Apple 的 DNA  之一。

但是,上述並不代表 Apple 會去迎合消費者。因為消費者的需求也不總是對的,而 Apple 在做的,是幫他們想到什麼是自己真正的需求。這種減法藝術,在 Apple 的產品上有很明顯的著力。

回到 Swift 語言的開發議題。既然 Apple 並不會刻意去迎合消費者,那我個人覺得:Apple 企圖吸納更多 Script 語言族群開發者的意圖的此類說法,似乎並不合理。事實上,對於習於 Objective-C 的 Mac OS/iOS 原生開發者而言,轉換到 Script 語言也不是一件成本低的事。

扣除 Web App 的開發途徑,原先能在 Mac OS / iOS 上進行開發能使用 C, C++ 及 Objective-C,再加上一些框架的話,也有使用 Ruby 或 JavaScript 的選擇。也就是說,如果 Script 族群的開發者想切入 Mac App 的市場,也早就有相關的方法,而 Apple 提供官方語言的作法,也不一定會被領情。

此外,早期開發 Mac 相關應用程式的族群和開發其他平台相關應用程式的族群,在個性及偏好上就不太是重複太多的一群,對於產出的風格、作法都有不一樣的表現。以目前 App Store 上的發展程度來看,Apple 對於其他原先外在的開發者族群,實在也沒有一定得納入其下的必要;反之,接下來對於 App 品質的審評反而會變得更困難才是。

那麼,倒底為什麼需要發展 Swift 呢?隨便猜猜好了…例如…未來 Safari 也能執行 Swift 嗎?(提供引擎,甚至能和 JavaScript 相轉換?)也就是說,反過來把 Web 也給統一了?

身為 Objective-C 的主要實作者的 Apple 倒底是怎麼佈這一步棋的哩…,就繼續看下去吧。