高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

retainCount of NSNumber

在Objective-C裡有一種記憶體管理機制叫做Reference Counting,是說當某個物件生成並初始化之後,它的retain count會設定成1。執行該物件的”retain”方法會讓該物件的retain count加1,而release方法會讓retain count減1。當該物件的retain count變成0的時候,這個物件自動會呼叫dealloc方法,然後把記憶體還回來,Objective-C的書上或是官方手冊裡差不多都是這樣教的。

所以,下面的程式碼,2個物件的retain count預期應該會是1:

1
2
3
4
5
NSNumber *n1 = [[NSNumber alloc] initWithInt: 10];
NSNumber *n2 = [[NSNumber alloc] initWithInt: 100];

NSLog(@"retain count of n1 is %i", [n1 retainCount]);
NSLog(@"retain count of n2 is %i", [n2 retainCount]);

輸出結果是:

retain count of n1 is 2
retain count of n2 is 1

n2的retain count是1沒問題,但n1的卻是2,這結果跟我想像的不太一樣,這令我這個初學者很困惑..我知道retainCount不應該被拿來做為流程裡的邏輯判斷的依據,不過我很好奇為什麼會有這樣的差異?

翻了一下網路上的討論,原來是說因為某些數字太常被用到,為了做一些最佳化,所以在系統裡直接就預先產生了一份,再試了一下以下的程式碼:

1
2
3
4
5
6
7
8
9
10
11
NSNumber *n1 = [[NSNumber alloc] initWithInt: 10];
NSLog(@"retain count of n1 is %i", [n1 retainCount]);

NSNumber *n2 = [[NSNumber alloc] initWithInt: 100];
NSLog(@"retain count of n2 is %i", [n2 retainCount]);

NSNumber *n3 = [[NSNumber alloc] initWithInt: 100];
NSLog(@"retain count of n3 is %i", [n3 retainCount]);

NSNumber *n4 = [[NSNumber alloc] initWithInt: 10];
NSLog(@"retain count of n4 is %i", [n4 retainCount]);

結果是:

retain count of n1 is 2
retain count of n2 is 1
retain count of n3 is 1
retain count of n4 is 3

又試著把他們的位址印出來:

1
2
3
4
5
// address of nums
NSLog(@"address of n1 is %p", n1);
NSLog(@"address of n2 is %p", n2);
NSLog(@"address of n3 is %p", n3);
NSLog(@"address of n4 is %p", n4);

結果是:

address of n1 is 0x100108e20
address of n2 is 0x10010cb30
address of n3 is 0x10010cb50
address of n4 is 0x100108e20

這樣似乎就能解釋retain count跟預期不太一樣的原因了,可以看到n1跟n4是指向同一塊記憶體位置,而n2跟n3是不同的位置,retain count都是1,表示n2跟n3在生成的時候是建立一個新的數字,而n1跟n4則是指向一個像是”預先產生而且共享”的數字,所以n1一開始的 retain count是2,n4因為指向跟n1同一個地方,所以retain count變3。而這個最佳化(預先產生)的範圍,似乎是從-1 ~ 12之間。

果然還有很多要學的 :)

新手上路,若有錯誤還請不吝指教!

Zenburn Color Schema for FlashBuilder

我的工作需要長時間看著電腦螢幕,除了用腦袋跟手指頭敲鍵盤之外,眼睛也容易疲勞,低對比(low-contrast)的Zenburn配色一直都是我喜歡的配色方式。近期因為使用Flash Builder在趕案子,雖然說也可以進到設定的地方自己手動一個一個的調顏色,但就是調不出我想要的那個樣子,不過網路上總是有許多強大的善心人士,有人把zenburn的color schema調出來,並做成設定檔可以讓大家來匯入。

安裝方法:

1. 記得千萬一定要先備份你自己的設定檔

因為下載來的設定檔,跟你自己原來工作的環境可能是不同的,包括快速鍵、workspace…等等的設定,我就是忘了備份就直接匯入別人的設定檔,結果搞得原來的設定都跑掉了,後來去time machine裡把舊的設定檔挖出來再覆蓋回去的..

匯出設定檔:

選擇File -> Export -> Other,點開General,裡面有個Preferences的選項,接著下一步:

image

你可以選擇Export All,或是只匯出你想要的設定即可:

image

再選擇一下匯出的位置,按下Finish就行了。

2. 下載zenburn for flash builder的設定檔

http://github.com/mnem/fb-zenburnish,在這個頁面底下有說明安裝方法

下載解壓縮後,裡面有個fb-zenburnish.epf跟README檔案(記得要看一下內容)。

如同剛剛匯出的步驟,只是這次是反過來操作。選擇File -> Import -> Other,在General裡找到Preferences選項,選擇你要匯入的epf檔案,沒問題的話按下Finish就完成了。

但 對我來說,因為我想要保留我自己習慣的設定,我只要zenburn的color schema設定就好,所以我的作法是用文字編輯器開啟剛下載的fb-zenburnish.epf後,把內容貼到我自己剛才匯出的設定檔的最後面,最後 再把修改過的設定檔匯回來,這樣我就可以保有我自己的設定以及zenburn的color schema了。

成果照:

image

對於長時間需要用眼力的人來說,不妨試試看效果,也許會比較輕鬆一些些(未經人體實驗證實,但至少對我來說是有用的)。不過顏色的喜好是很主觀的,也許我覺得喜歡顏色配置的對其它人來說反而可能比預設的更糟或更傷眼..

另外,我也手癢的把Xcode改成zenburn配色了:

  1. 下載:http://mac.softpedia.com/get/Graphics/Xcode-Zenburn-Theme.shtml
  2. 把下載的xccolortheme檔案複製到 ~/Library/Application Support/Xcode/Color Themes/ 底下
  3. 開啟Xcode,進入Preferences的Fonts & Colors項目,在下拉選單就可以看到zenburn的選項了

成果照:

image

Ruby on Rails 之門外漢心得

image

這不是討戰文,也不是一篇討論程式語言的誰優誰劣的文章,僅就我個人這半年來使用Ruby on Rails(以下簡稱RoR,不是那個那個RO線上遊戲)用在工作上的一些簡單的心得跟大家分享。

很多廠商喜歡做網路活動來促銷新商品、打知名度或是跟網友拉近距離。目前廠商們比較愛的網路活動,大概有上傳照片、影片、票選、轉寄、推薦..等,而隨著” 社會的進步”,客戶們也”得跟上時代”,都不免俗的要跟FB或plurk弄在一起,而我的工作,主要就是幫客戶處理這樣的需求。(我想這段我的同業應該知道我不是在講真心話!)

就我而言,我個人比較熟悉的程式語言算是ActionScript 2/3,大部份的工作也都是跟紅紅的Flash為伍。但後來的網路活動越弄越複雜,單純的Flash已經不見得夠用了,很多時候得跟server端交換資料。

從最早的ASP,後來換到PHP,其實都還不錯用,也沒什麼問題(不然PHP現在不會有這麼大的市佔率)。後來試著用PHP的Zend Framework,因為現在比較流行的web framework都有照著MVC(Model-View-Controller)的樣子來打造,寫起來程式碼跟頁面有更清楚的感覺。

2009年試著換到PythonDjango,它也是MVC的實作,感覺還不賴,有種程式寫起來可以打更少字的感覺。而且它所謂的batteries included,只要把一些設定打開,後台管理功能就直接做起來了,相當方便。

2010年起,我試著開始把案子用RoR來做,整個有種「我終於可以把時間花在吃喝玩樂寫AS上了」的感覺了。

以下是一些大家可能會有的疑問:

Q: 為什麼你要一直換?

A: 我是善變的人 :)

Q: 你是寫AS的,為什麼要自己寫server端的程式?

A: 情況允許的話當然我也想跟別人一起合作寫,不過網路活動很多都是急件,而且客戶通常不太會管你六日週末要不要休假。後來發現其實自己寫真的還挺快的,而要什麼資料或是要接什麼資料都可以自己加一下就搞定,免看人臉色。

Q: RoR是一種程式語言嗎?

A: 不是,它是一種web framework,它本身用的程式語言是Ruby。

Q: RoR要錢嗎?

A: 不用的,而且你有興趣的話,還可以取得完整的原始碼,印出來上廁所的時候閱讀 :)

Q: 為什麼用RoR來開發會快?

A: 以下的動作我先假設開發的工程師有一些RoR的開發經驗。

以一個發票登錄的程式來說,假設它需要使用者姓名、電話、地址、Email及發票號碼等幾個欄位,我的動作就是先建立一個Model來對應這些欄位(這動作 大概1~2分鐘左右可完成)。再來就是建立一個Controller來準備接收使用者submit出來的動作(大概1~2分鐘左右),而實際在 Controller裡寫的程式碼,也就是把Model給叫出來,把使用者post的資料餵進去,程式碼如下:

1
invoice = Invoice.new(params[:invoice])

最後再一個save的動作:

1
invoice.save

差不多就搞定了(這動作大概1分鐘左右可完成)

剛剛這些資料庫寫入的動作,再加上一些if..else..的判斷,大概10行程式碼有找。整個發票程式部份,不包含設計的話,大概5分鐘能寫完,也許如果再加個發票重複登錄判斷的驗證,最多應該10分鐘搞定。

那要怎麼把資料庫裡的東西撈出來? 通常只要一行:

1
invoice = Invoice.all

(大概3~10秒,依打字速度不同而有差異)

那要怎麼樣把它餵給Flash? RoR的ActiveRecord有支援直接輸出成XML或JSON的方法,簡單的可以直接用invoice.to_xml 或invoice.to_json 就行了(大概10秒),複雜一點的,也可以用xml builder來建個模板給它(看複雜程度,大概5分鐘內搞定)。

藉由ORM(Object-Relational Mapping)的包裝,把原本要用SQL操作的動作,都改用物件的方式來操作。而大部份的網路活動的寫入/查詢語法都挺單純,沒意外的話應該都不用自己寫 SELECT * FROM 或是 INSERT INTO之類的東西了,不只操作簡單,也可避開SQL Injection的麻煩。

另外RoR的另一大優點,就是它有相當多好用的外掛(plugin),而且幾乎都是免費可以取得的(包括原始碼)。

一樣以網路活動上傳照片這個來舉例,上傳照片之後,通常得自動再產生一些比較小尺寸的縮圖,可能還要裁切一下圖片。透過某個方便的外掛(paperclip),上面這些動作,真正要寫程式好像不到5行吧,搞定之後會有種「哇賽!怎麼就這樣就可以了?」的驚奇感。

再例如上傳照片後,資料一多,前端呈現的頁面通常就得有分頁的功能,而這功能透過某個方便的外掛(will_paginate),大概只要多加一行程式碼就可以搞定分頁的工作。

Q: 可是你知道,做網路的活動,客戶很愛改來改去…RoR改起來會不會很麻煩?

A: 網路活動的特性,就是變動性高。除了設計部份可能會被改來改去外,一會可能要你加個中獎名單,一會說這個頁面要放到另一個頁面之後…愛改來改去這件事,我想這個是許多同業的痛!

老實說,就以上面的例子來說,就算整個砍掉重練,也不見得花多少時間;如果是修改流程,說不定改一下route規則就可以技巧性的處理掉了,其實面對愛改來改去的狀況,RoR還是個不錯的應對工具。

Q: RoR效能好嗎?

A: 我沒比較過所有家的程式語言以及web framework,所以我沒辦法下這個結論。通常如果遇到效能差或是資料庫負載很吃重的地方,可以把它做cache或產出靜態頁面來提昇效能,而做 cache或是把cache給expire掉的動作,在RoR裡是很容易做的。

Q: 那,Ruby好寫嗎?

A: 我以AS程式碼來舉個例子:

1
2
3
4
if (my_age >= 30)
{
  trace("you're so old!");
}

改用ruby寫的話:

1
2
3
if my_age >= 30
  puts "you're so old!"
end

基本上少了小括號、大括號,也不用分號結尾,至少就可以少打好些個字,甚如果想要的話,if也可以放到後面:

1
puts "you're so old" if my_age >= 30

如何? 看起來更像一般的英文吧!

再例如如果我想要印出3天前的日期,有的程式語言可能要先new一個Date物件出來,再透過一些method可以取得日期。在Ruby裡,只要用3.days.ago就行了。3? 它不是數字嗎? 是的,你沒看錯,在Ruby裡什麼東西都是物件,包括數字也是,所以你可以對3這個物件呼叫方法,再來個例子:

1
2
3
3.times do
  puts 'hello'
end

猜得出來它在幹嘛嗎? 它就是把”hello”這個字串印3遍..

其它關於這個程式語言的細節,如果想了解更多,可參考Ruby的官網,有相當多的文件可以看。

Q: 在Flash裡可以用AMF的格式與server端溝通,RoR能做嗎?

A: 可以的,請參考http://blog.eddie.com.tw/2010/03/18/rubyamf

Q: 還有什麼好處?

A: 前面提到,由於大部份的客戶想要做的東西都差不多,例如發票登錄來說,可以的話,也可以把這些常用的功能也做成「發票plugin」,也許下次要用的時候,就把plugin裝上去,可能再做一些微調就行了。

Q: 那,好維護嗎?

A: 基本上RoR的骨架是依照MVC的架構來實做的,所以某A或某B寫的程式碼,只要寫的人不要用太奇怪的寫法,大概都可以知道XX程式或XX功能會放在哪裡(當然改不改得動是另一回事)。重點是,很多網路活動都是短期的,活動結束就會下架,老實說並沒有太多所謂的維護的問題 :)

Q: RoR好像被我講得很神,那它缺點是什麼?

1. 它的學習曲線的高低決定於開發者的背景知識跟經驗

如果你之前就有用別的程式語言開發過網站,那RoR對你來說應該會比較快上手;如果你對於什麼是Form、什麼是GET/POST還不清楚的話,那這個對你 來說可能會有些吃力,很容易卡關。特別是如果沒有個導師帶入門,還真的很容易碰壁。 (PS: 其實最好還有一些*nix的操作經驗,以及熟悉一些版本控制系統如SVN或Git)

2. 台灣的hosting比較不好找

台灣目前使用的人口還是相當少,國外雖然有比較多的solution,但客戶的網路活動的TA大部份都是在台灣,可能會有連線速度不夠快的問題。這個我解決的方法就是,我自己弄一台機器放機房,自己弄環境起來 :)

結論

綜合以上各項優缺點,我真的覺得RoR挺適合拿來做網路活動,當然做長期的官網也合適,這裡就我自己工作上常遇到的狀況提供一些建議。

以上,僅以我這半年來用RoR的一些小小心得與大家分享,我也還是個一隻腳剛踏進去的新手門外漢,內容若有誤再請前輩、神人們不吝指教 :)