C#, Java, Objective-C (iOS 5以前) 三種語言的 Property與Field 介紹

C#, Java, Objective-C (iOS 5以前) PropertyField 介紹

很久以前就想寫這篇文章了,在我得知我都亂用Objective-CProperty之後Orz
下面是我的心得,不一定正確

在物件導向的世界有兩個Termfieldproperty。定義不知道是不是field只能給自己人使用,而property則是此物件要讓外部的Class存取的屬性。原本property的用意就是封裝,不讓外部的元件亂設定自己的屬性,或是你要設定之前,我再幫你檢查一次,ex: Id (身分證) 這個欄位,你可能就只能設定某些值~

首先是C#
private string _Msg;   //這是field
public string Msg       //這是property
{
     get                         //getter
    {
         return _Msg;
     }
     set                         //setter
     {
         _Msg = value;
     }
}
上面可以看到 property的寫法很累綴,所以C#又有另一種寫法
public string Msg
{  get; set;  }
這樣子你也不用另外定義一個 field了。由Compiler自動幫你產生。而外部使用的時候則是
classA.Msg = "Hello";
return classA.Msg;
這裡我很推薦的就是C#是使用 "=" 來呼叫 setter的,這樣直覺多了。也因為這個原因,我有時候會不使用property,而直接使用field
public string Msg;
自己的想法是,外部元件使用ClassA時是一樣的寫法(IntelliSense會看到不一樣),然後我也不需要filter,所以不必為了propertyproperty不知道這樣設計會有甚麼問題?

接下來是Java

public class ClassA{
        string Msg;                      //這是field
        public string getMsg()    //這是property
        {
                return Msg;
}
public void setMsg(string _Msg)
{
        Msg = _Msg;
}
}

Java 很嚴謹Orz,所以要使用的時候,一定要使用function的呼叫
        classA.getMsg();
        classA.setMsg("Hello");
我自己是覺得這種寫法很麻煩啦,每次都要多打一個get / set,然後某些屬性又沒有get ex: Array.size() or xxx.length() 這裡我不太確定他的函式命名方式,因為readonly property就不用加上get嗎?
所以我有時候還是偷懶直接用field
public String Msg;

第三個是 Objective-C
新的iOS 5 不適合下面的寫法了,因為有新的記憶體管理方式
要先介紹的是在iOS 5以前,iOS是使用 Reference Count的記憶體管理方式,所以如果你要用這個object的話,你就要記得幫他refCount+1,不用時 -1,當他的refCount=0時就會自動釋放。

classA.h
@interface ClassA: NSObject {
    NSString *Msg;      //這是field
}

- (NSString*)getMsg;                        //這是getter property
- (void)setMsg:(NSString*)_Msg;    //這是setter property

乍看之下跟Java很像,當然如果你都是用這種手工的方式就沒有甚麼問題。自己實作的Property Function記得要 add refCount
呼叫的寫法就是

[classA setMsg:@"Hello"];
NSString *Tmp = [classA getMsg];

但後來Compiler提供了快速宣告的做法
ClassA.h
@interface ClassA: NSObject {
    NSString *Msg;      //這是field
}
@property (nonatomic, retain) NSString *Msg     //這一行就是幫你產生上面的例子的那兩個Property Function 的宣告

ClassA.m
@synthesize Msg
@synthesize則是幫你產生 Property Function的實作。

Objective-C 也提供了"."的語法
self.A = @"Hello";  Compiler 會轉為 [self setA:@"Hello"];
return self.A 則是轉為return [self A];

到這裡用法應該沒甚麼問題,但該死的就是 Reference Count 的設計,他的理念是,如果你想繼續使用某個物件的話,你就要記得幫他+1,不再用了之後就要-1。所以在自動產生的setter第一行就會作這件事情。
所以如果你直接用  Msg = anotherMsg; self.Msg = anotherMsg; 是不一樣的,一個有呼叫setter,一個沒有,如果anotherMsg被釋放之後你再用他就會掛掉了。

第二種情況則是釋放不完全,浪費記憶體空間
self.classB = [ClassB new];
new的時候剛產生出來的物件 refCount 1,丟到 setter 之後,會變成2,將來不再使用的時候,呼叫 self.classB = nil,會將其 refCount-1 變成1,但永遠不會變成0被釋放了Orz,因為沒有指標指到ClassBnew出來的那塊記憶體了。

所以我後來的寫法都改成
self.classB = [[ClassB new] autorelease];

目前是習慣大都加上 self. 來使用property,幾乎不用 field了。但還是要提一下另一種寫法,好像是從C++傳過來的
ClassA.h
@interface ClassA: NSObject {
    NSString *_Msg;    //這是field
}
@property (nonatomic, retain) NSString *Msg     //這一行就是幫你產生上面的例子的那兩個Property Function 的宣告

ClassA.m
@synthesize Msg = _Msg;
就是fieldproperty不要用相同的名字,這樣如果你忘了寫"self." Compiler就會通知你。但我是都沒用這樣啦,覺得有點麻煩~

最後我發現沒宣告field也可以。所以下面是我的最終版:
ClassA.h
@interface ClassA: NSObject {
}
@property (nonatomic, retain) NSString *Msg     //這一行就是幫你產生上面的例子的那兩個Property Function 的宣告

ClassA.m
@synthesize Msg;

直接宣告 Property就好~


題外話:

不知道有沒有人跟我一樣之前覺得Objective-Cfunction 定義很奇怪的,我後來終於想到有一個唯一的好處
如果我有一個function,需要接收兩個 string 的參數,然後第二個string argument有可能是不同的意義,在C#是做不到的,因為它只用parameter type去作判斷。
- (void)GetWebContent:(NSString*)Url RefererUrl:(NSString*)RefererUrl
- (void)GetWebContent:(NSString*)Url LoginUrl:(NSString*)LoginUrl


留言

這個網誌中的熱門文章

好貴的東元冷氣維修--馬達啟動電容

台大醫院 婁培人 耳鼻喉科 就診

機車無法充電之整流器壞掉--$650