52個有效方法(7) - 在對象內部儘可能直接訪問實例變量

在對象內部儘可能直接訪問實例變量

在對象內部讀取數據時,應該直接經過實例變量來讀,而寫入數據時,則應經過屬性來寫。atom

  • _name = @"Jack"不通過setter的消息發送,直接爲變量賦值,速度快。
    對於如下的 name 屬性:@property (nonatomic, copy) NSString *name;
    直接賦值是:_name = @"Jack"; ,經過 self.name = @"Jack"其實等同於_name = @"Jack".copy
  • self.name = @"Jack" 會觸發KVO,_name = @"Jack"不會
    -self.name = @"Jack" 能夠在 setter 方法中進行斷點調試,每次賦值你都知道。
  • 因此有一種合理折中方案就是,讀取數據的時候用 NSString *str = _name,賦值用 self.name = @"Jack"

在對象內部訪問實例變量時,是經過屬性(self.proper)來訪問仍是經過_proper來訪問區別在因而否執行屬性的settergetter方法。調試

  • 若是執行屬性的settergetter方法,則經過_proper來訪問。rest

  • 若是未執行屬性的settergetter方法,則經過屬性(self.proper)來訪問。
@interface Wrestler : NSObject
 
@property (copy, nonatomic) NSString *name; // 將name聲明爲屬性
 
- (void)smell;
 
@end
 
@implementation Wrestler
@synthesize name = _name; // 屬性name能夠使用實例變量_name直接訪問
 
- (void)setName:(NSString *)aName {
    NSLog(@"Set name");
    _name = [aName copy];
}
 
- (NSString *)name {
    NSLog(@"Get name");
    return [_name copy];
}
- (void)smell {
    NSLog(@"*** Smelling ***");
    
    // 使用dot syntax訪問實例變量
    NSLog(@"%@", self.name);
    
    // 直接調用屬性的getter方法
    NSLog(@"%@", [self name]);

在初始化方法及dealloc方法中,老是應該直接經過實例變量來讀寫數據。code

  • 子類可能複寫setter方法,用 self.proper = @""可能不等同於_proper = @"".copyorm

  • 咱們寫一個Wrestler的子類Cena,該類繼承了屬性name並重寫了其setter方法,該方法會先檢驗名字後綴是否爲Cena,不然拋出異常。
@interface Cena : Wrestler
 
- (instancetype)initWithName:(NSString *)aName;
 
- (void)wrestle;
 
@end
 
@implementation Cena
@synthesize name = _name;
 
- (instancetype)initWithName:(NSString *)aName {
    self = [super init];
    
    if (self) {
        NSLog(@"self.name = aName");
        self.name = aName;
    }
    
    return self;
}
 
- (void)wrestle {
    NSLog(@"I'm %@, U can't see me", self.name);
}
 
- (void)setName:(NSString *)aName {
    if (![aName hasSuffix:@"Cena"]) {
        [NSException raise:NSInvalidArgumentException format:@"last name must be Cena"];
    }
    
    _name = [aName copy];
}
 
@end
  • 在父類Wrestler的init方法中將name初始化爲空白字符串@""
(instancetype)init {
    self = [super init];
    
    if (self) {
        NSLog(@"self.name = empty string");
        self.name = @"";
    }
    
    return self;
  • 調用
Cena *cena = [[Cena alloc] initWithName:@"John Cena"];
        [cena wrestle];
  • 運行崩潰。緣由:self.name = @"";。調用子類中覆寫的namesetter方法,空白字符串明顯沒有@"Cena"後綴,從而拋出異常。

使用Lazy Initialization配置的數據,應該經過屬性來讀取數據。對象

@property (strong, nonatomic) NSNumber *chamCount;
- (NSNumber *)chamCount {
    if (!_chamCount) {
        _chamCount = @13;
    }
    
    return _chamCount;

不要在setter/getter方法中調用setter/getter方法繼承

  • 將上面的setter方法修改:
- (void)setName:(NSString *)aName {
    NSLog(@"Set name");
//    _name = [aName copy];
    self.name = aName;
}
  • 運行程序,控制檯不停輸出Set name,崩潰。
  • 緣由:setter方法中調用setter方法會不斷嵌套調用,最終致使程序崩潰。getter方法同理。

要點

  1. 在對象內部讀取數據時,應該直接經過實例變量來讀,而寫入數據時,則應經過屬性來寫。字符串

  2. 在初始化方法及dealloc方法中,老是應該直接經過實例變量來讀寫數據。get

  3. 使用Lazy Initialization配置的數據,應該經過屬性來讀取數據。string

  4. 不要在setter/getter方法中調用setter/getter方法。

相關文章
相關標籤/搜索