1. 程式人生 > >OC MRC 成員變數, property, synthesize, dynamic

OC MRC 成員變數, property, synthesize, dynamic

iOS @property、@synthesize和@dynamic

MRC 環境下: 建立一個 Person 類,  有 name, age, gender, weight 屬性:

最早的寫法: 成員變數

.h 檔案
@interface Person : NSObject
//成員變數, 按蘋果程式碼規範要帶下劃線, 以便和 setter, getter 方法的引數區分
{
    NSString *_name;
    NSString *_gender;
    NSInteger _age;
    CGFloat _weight;
}

//宣告 setter, getter 方法
- (void)setName:(NSString *)name;
- (NSString *)name;

- (void)setGender:(NSString *)gender;
- (NSString *)gender;

- (void)setAge:(NSInteger)age;
- (NSInteger)age;

- (void)setWeight:(CGFloat)weight;
- (CGFloat)weight;

@end
.m 檔案
@implementation Person

    //實現 setter, getter 方法
    - (void)setName:(NSString *)name {
        _name = name;
    }
    - (NSString *)name {
        return _name;
    }

    - (void)setGender:(NSString *)gender {
        _gender = gender;
    }
    - (NSString *)gender {
        return _gender;
    }

    - (void)setAge:(NSInteger)age {
        _age = age;
    }
    - (NSInteger)age {
        return _age;
    }

    - (void)setWeight:(CGFloat)weight {
        _weight = weight;
    }
    - (CGFloat)weight {
        return _weight;
    }

@end

Xcode 4.4 之前的寫法: property 和 synthesize 共用

Xcode4.4版本之前: @property 和 @synthesize的功能是獨立分工的

  • @property的作用是: 生成成員變數 set/get 方法的宣告

      @property int age; 它的作用和下面兩行程式碼的作用一致
      - (void)setAge:(int)age;
      - (int)age;
      //注意:屬性名稱不要加字首_ 否則生成的get/set方法中也會有下劃線
      //屬性中帶有下劃線 _ 那麼生成的get/set也會有下劃線 _
      //@property int _age;
      //- (void)set_age:(int)_age;
      //- (int)_age;

 

  • @synthesize的作用

      //@synthesize age//實現 @property 宣告的 set/get 方法, 生成私有的成員變數 age(不帶下劃線)

      生成帶下劃線的成員變數
      @synthesize age = _age//實現 @property 宣告的 set/get 方法, 生成私有的成員變數 _age

      //如果在.h檔案中沒有定義 _age 成員變數的話,就會在.m檔案中自動生成@private型別的成員變數_age

.h 檔案
@interface Person : NSObject

@property (nonatomic, assign) NSString *name;//相當於擁有了以下兩個方法的宣告
//- (void)setName:(NSString *)name;
//- (NSString *)name;

@property NSString *gender;//相當於擁有了以下兩個方法的宣告
//- (void)setGender:(NSString *)gender;
//- (NSString *)gender;

@property NSInteger age;//相當於擁有了以下兩個方法的宣告
//- (void)setAge:(NSInteger)age;
//- (NSInteger)age;

@property CGFloat weight;//相當於擁有了以下兩個方法的宣告
//- (void)setWeight:(CGFloat)weight;
//- (CGFloat)weight;

@end
.m 檔案
@implementation Person 

    @synthesize name = _name, gender = _gender, age = _age, weight = _weight;

    或分開寫:
    @synthesize name = _name;//相當於以下兩個方法
    //- (void)setName:(NSString *)name {
    //    _name = name;
    //}
    //- (NSString *)name {
    //    return _name;
    //}

    @synthesize gender = _gender;//相當於以下兩個方法
    //- (void)setGender:(NSString *)gender {
    //    _gender = gender;
    //}
    //- (NSString *)gender {
    //    return _gender;
    //}

    @synthesize age = _age;//相當於以下兩個方法
    //- (void)setAge:(NSInteger)age {
    //    _age = age;
    //}
    //- (NSInteger)age {
    //    return _age;
    //}

    @synthesize weight = _weight;//相當於以下兩個方法
    //- (void)setWeight:(CGFloat)weight {
    //    _weight = weight;
    //}
    //- (CGFloat)weight {
    //    return _weight;
    //}

@end

 

Xcode4.4之後: @property 代替了 @synthesize的功能
 

     @property 的作用:

  1. 生成了成員變數 get/set 方法的宣告
  2. 生成了私有的帶下劃線的的成員變數因此子類不可以直接訪問,但是可以通過get/set方法訪問。那麼如果想讓定義的成員變數讓子類直接訪問那麼只能在.h檔案中定義成員變量了,因為它預設是@protected
  3. 生成了get/set方法的實現 

     注意:

  1. 當讓系統自動生成setter 以及 getter 方法實現時,此時系統會自動生成例項變數
  2. 如果我們自己重寫了setter 和 getter 方法其中之一時,系統還會自動生成例項變數
  3. 如果我們自己重寫了setter 和 getter ,那麼此時系統不再自動生成例項變數,需要我們自己建立例項變數,或者使用@sythesize來生成例項變數, 此時的例項變數是私有的

//@sythesize 在.m檔案中的作用:

    //(1)生成setter 和 getter 方法的實現
    //(2)生成內部操作的例項變數

.h 檔案
@interface Person : NSObject

@property (nonatomic, retain) NSString *name;

@property (nonatomic, copy) NSString *gender;

@property (nonatomic, assign) NSInteger age;

@property (nonatomic, assign) CGFloat weight;

@end

注意: 當使用屬性時, 為了防止記憶體洩露, 不同語義特性 retain, copy, assign 修飾的屬性, 其 setter , getter 的內部實現有所不同

注意retain, copy 修飾的屬性的 setter, getter 方法的實現

#pragma mark --- 不同語義特性下的setter 和getter 的內部實現
#if 0
//assign,系統預設
//setter 方法
- (void)setName:(NSString *)name {
    _name = name;
}

//getter 方法
- (NSString *)name {
    return _name;
}
#endif

#if 0
//retain
//setter 方法
- (void)setName:(NSString *)name {
     if (_name != name) {//避免重複操作
        [_name release];//解決記憶體洩露問題
        _name = [name retain];//解決野指標問題
    }
}
//getter 方法
- (NSString *)name {
    return [[_name retain] autorelease];//蘋果推薦的getter方法的安全處理機制
}
#endif

#if 0
//copy
//setter 方法
- (void)setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}
//getter
- (NSString *)name {
    return [[_name retain] autorelease];
}
#endif

@dynamic

@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由使用者自己實現,不自動生成。假如一個屬性被宣告為 @dynamic var,而且你沒有提供 @setter方法和 @getter 方法,編譯的時候沒問題,但是當程式執行到 instance.var = someVar,由於缺 setter 方法會導致程式崩潰;或者當執行到 someVar = var 時,由於缺 getter 方法同樣會導致崩潰。編譯時沒問題,執行時才執行相應的方法,這就是所謂的動態繫結。