• 52个有效方法(7)


    在对象内部尽量直接访问实例变量

    在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。

    • _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来访问。

    • 如果未执行属性的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方法中,总是应该直接通过实例变量来读写数据。

    • 子类可能复写setter方法,用 self.proper = @""可能不等同于 _proper = @"".copy

    • 我们写一个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方法中,总是应该直接通过实例变量来读写数据。

    3. 使用Lazy Initialization配置的数据,应该通过属性来读取数据。

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

  • 相关阅读:
    收藏CSS经典技巧
    理解这26句话将不再烦恼
    包转发率得计算和背板带宽的计算
    mysql 建表 AUTO_INCREMENT , 数据类型 VARCHAR
    Linux Wine with *.bat *.exe ( Photoshop and etc.. )
    [转载]expect spawn、linux expect 用法小记
    sqlmap.py Database injection and hak
    xls===>csv tables===via python ===> sqlite3.db
    sftp 服务器外网访问设置
    vsftp FTP服务器外网访问设置
  • 原文地址:https://www.cnblogs.com/shikaiming/p/11681013.html
Copyright © 2020-2023  润新知