2012年10月2日 星期二

@property 與 @synthesize


原文為 堤刻科技技術長 分享給同仁的信件

----------------------------

今天還是很基本的地方, 設 @property 和 @synthesize 從很粗淺的地方開始說,
他們就是幫開發者建立一對可以存取該變數的 function, 假設有一個變數叫做

NSString *myString;

然後我幫他配置了

.h 裡面的
@property (nonatomic, retain) NSString *myString;

.m 裡面的
@synthesize myString;

在這個當下, 就相當於聲明了

用以 get 的 function
-(NSString*) myString {
     return _myString;
}

用以 set 的 function
-(void) setMyString : (NSString*) newValue {
     [newValue retain];
     [_myString release]; //文件中說明到, 如果當 _myString 為 nil 時, nil 做 release 這個動作是合法, 並且不會出問題的.
     _myString = newValue;
}

另外, 在這樣的情況下,

myString = xxx;



self.myString = xxx;

的意義是不相同的, self.myString = xxx; 會被轉換成 [self setMyString:xxx];
所以,

myString = [[NSString alloc] init];

不會造成 leak,

self.myString = [[NSString alloc] init];

一寫出來, 瞬間就 leak 了。


舉另外一個常用的例子說,

UILabel *myLabel;

不管是用 myLabel.text = xxx; 或是 [myLabel setText:xxx]; 都不會造成 leak.

有了這些基本的知識以後, 才有辦法去了解 @property 後面參數的含意,
從分類上來說, 其實是有三類,

1. 可不可以讀寫 readwrite or readonly,
- 預設是 readwrite, 因此, 通常很少在我們的扣看到這個, 他同時會產生 set 跟 get.
- readonly 的話表示這個變數只能被讀取, 他只產生 get, 並且會在你想亂 set 的時候, 在 compiler 階段報錯.

2. 存的方法 strong or weak or copy or assign or retain, 注意, 我說的是存的方法, 因此只影響 set 時的動作,
先從比較容易的開始說,

- retain, 上面那個舉例的 set function 就是他的形態, 他會 retain 新的東西, release 掉舊的,
然後把自己設成新的東西.
- copy, 如同 retain, 只是 copy 會把新的東西做 copy, 而不是做 retain.
- assign, 就是很單純的將本身設成新的東西, 不做 retain 也沒有 copy, 喔對了, 如果什麼都沒寫的話, assign 是預設.
- strong 跟 weak 我也不是太懂, 從 document 裡面我也看不太出來他跟 retain 究竟有多大的差異,
反正比較少用, 所以以後再來看.

3. 原子小金剛, 我不知道該怎麼翻譯 nonatomic or atomic.....這其實是個有深大意義, 但是我們以前都沒有發現的參數,
最一開始的時候只知道 nonatomic 比較好.....

- 比較常用就先從 nonatomic 開始說, nonatomic 在 iphone 開發上是被推獎的, 因為他比較快, 比較單純, 
比較適合 single-thread, 但是就表示, 他在 multi-thread 是有缺陷的, 比方說 A 進了 get function,
他沒有辦法阻攔 B, C, D 同時在做 set 的動作, 所以最後你不確定你得到的值是 A 原來想拿的那個, 
或者是 B, 或者是 C, 或者是 D, 然後就會 debug 到發瘋.

- 相對的 atomic 就會幫你在 multi-thread 的時候多做一點處理, 如果 A 在 get, 那麼 B, C, D 想 set 都會被擋住,
直到 A 把東西拿走之後, 才繼續給 B, C, D 使用.

最後, 其實也可以從頭到尾都不寫 @property 跟 @synthesize, 只要你可以控管好你每一個變數的使用就可以了.



reference by : 
The Objective-C Programming LanguageAdvanced Memory Management Programming Guide
Atomic vs nonatomic properties

NSLock 與 @synchronized 的不同

原文為 堤刻科技技術長 分享給同仁的信件

--------------------

今天重新再看過一次一些比較基本的 document, 把死背的東西部分的重新消化過一次,
其中有一個可能比較有趣的地方應該是 NSLock 和 @synthesize, 如果這個世界只有單 thread,
那麼我的 function 只要這樣寫

-(void) myFunction {
    NSLog(@"%d", count++);
}

然後我用一個 for 到 100 的迴圈去跑他的時候, 他可以按照順序的從 0~99 乖乖的排好,
但是當我 thread 變多的時候, 同時間衝進來拿到 count 這個數字的人可能就不只有一個,
所以通常的狀況就會是跑不滿到數字 99 就停了, 這個 function 有被執行 100 次,
只是最後的數字不會是 99.

在 obj-c 裡面提供了一個簡單而好用的做法, 讓開發者可以不用花太多心力, 
而能保持同一個程式碼區段的單一性, 只要在這個 function 裡面的部份加上

-(void) myFunction {
    @synchronized (self) {
        NSLog(@"%d", count++);
    }
}

那麼, 數字又會乖乖的從 0~99 排好, 即使是在 multi-thread 的情況下,
但是, 如果我把這段程式碼改成用 NSLock 來表達會變得怎麼樣?
假想起來會是這麼寫的

-(void) myFunction {
    if ([lock tryLock]) {
        NSLog(@"%d", count++);
        [lock unlock];
    }

}

想起來還蠻合理的, 就是當有人進來, 我就試試能不能鎖, 可以鎖的話我就開始做,
等做完之後再把他解鎖給下一個人用, 但是其實錯了~ O3O
因為在 multi-thread 的情況下, 所有的人都直接衝進這個 function, 當第一個人進去之後,
他就把門鎖上, 其他的人都因為進不去, 直接的就結束 function 了, 因此,
只會被 run 一次, 如果要從 NSLock 去做到 @synchronized的效果也是可以,
不過就要花費更多的程式碼在這上面, 不如使用 @synchronized.

所以雖然都是保護程式碼區塊的功能, 但是他們還是有些微的差異,

當我想要每一個進來這個 function 的人都依序執行的話, 那麼選擇用 @synchronized

當我想要防止這個 function 重複 call, 還沒有執行完就猛摳猛摳的囉嗦鬼, 那麼選擇用 NSLock