美文网首页
ios属性知识梳理

ios属性知识梳理

作者: 乖乖Learning | 来源:发表于2018-05-15 16:20 被阅读0次

    其实对于基础知识的掌握还是很重要的,很多次都被属性声明绕的有点晕。索性做个总结,网上找了其他大牛的总结作为参考。下面进入正题:
    1.通过self.name和_name获取局部变量的区别

    @interface Person : NSObject
    
    @property (nonatomic, copy) NSString* name;
    @property (nonatomic, assign) NSUInteger age;
    
    @end
    
    @implementation Person
    
    @synthesize name = _name;
    @synthesize age = _age;
    
    @end
    

    上述代码,在xcode6以后 @synthesize部分可以省略。下面说一下_name和self.name的区别。
    在Person对象实例化的时候,假设有一个person对象,此时编译器会自动生成_name这个变量,用来存储name这个属性。通过_name可以直接访问变量的name属性。
    而self.name本质是调用实例对象属性的setter方法和getter方法。从而访问name属性。
    2.setter方法和getter方法。
    属性方法遵守一个简单的命名约定。getter的名字与属性名相同(如:属性名为date则getter的名字也为date),setter的名字则是属性名字加上set前缀并采用驼峰命名规则(如:属性名为date则setter的名字为setDate)。布尔类型的属性还可以定义一个以is开头的getter方法,如:

    @property (readonly, getter=isBlue) BOOL blue;
    

    可以这样理解,对对象中的属性进行读和写。就是对应的getter方法和setter方法。如果确定了对象的一项属性,那么使用property关键字声明之后,系统会自动生成对应的setter方法和getter方法。当然你也可以通过重写这两个方法来实现更多的功能。

    @interface Person : NSObject
    {
        NSString *_name;
        NSUInteger _age;
    }
    
    - (void)setName:(NSString*)name;
    - (NSString*)name;
    - (void)setAge:(NSUInteger)age;
    - (NSUInteger)age;
    
    @end
    
    @implementation Person
    
    - (void)setName:(NSString*)name {
    //dosomething
        _name = [name copy];
    }
    
    - (NSString*)name {
        return _name;
    }
    
    - (void)setAge:(NSUInteger)age {
    //dosomething
        _age = age;
    }
    
    - (NSUInteger)age {
        return _age;
    }
    
    @end
    

    3.合成存取方法:@property
    如若为每一个变量都写setter和getter无疑是很繁琐和没有必要的。此时合成存取方法就出现了。使用@property声明变量之后,会自动生成这两个方法,如果有必要,再进行重写,不然就按照默认的规范名称来访问属性。
    可以这样理解,对象是一个变量,对象的变量里面也有name和age这样的变量,他们都需实现存取方法,那就将他们设置为属性。(合成了存取方法)。用@property进行声明,系统就默认生成对应的存取方法了。
    注意:在声明一个属性(property)的时候尽量使用Foundation框架的数据类型,如整形使用NSInteger或NSUInteger表示,时间间隔的浮点类型使用NSTimeInterval表示,这样代码数据类型更统一。

    4.懒加载
    所谓懒加载,其实就是重写属性的getter方法,在属性被访问,或者被使用到的时候,再进行加载,节省系统资源
    应用场景:

    @interface XMGTopicViewController ()
    @property (nonatomic, strong) NSMutableArray *users;
    @end
    
    @implementation XMGTopicViewController
    - (NSMutableArray *)users  //1部分
    {
        if (!_users) {                       //2部分
            _users = [NSMutableArray array];   //3部分
        }
        return _users;                  //4.部分
    }
    
    // 加载网络数据
    self.users = [LXBUsers objectArrayWithKeyValuesArray:responseObject[@"user"]];
    

    第一部分:self.users是一个getter
    第二部分:不能写成 !self.users 这也是一个getter,getter中有getter会造成死循环
    第三部分:可以使用self.users,这是一个setter
    此处如果按照_users方法编写不会调用setter方法,如果自定义setter方法需要完成一些事情建议使用self.users的方式来设置
    第四部分:不能使用self.users,这也是一个getter,getter中有getter会造成死循环
    可以参照本文开头第一点理解懒加载写法。

    接下来是重点部分:
    5.对于@property的指示符
    栗子:

    @property(nonatomic, readonly, strong) NSMutableArray *users;
    

    ① nonatomic atomic:
    指定合成存取方法是否为原子操作,可以理解为是否线程安全,但在iOS上即时使用atomic也不一定是线程安全的,要保证线程安全需要使用锁机制;
    可以发现几乎所有代码的属性设置都会使用nonatomic,这样能够提高访问性能,在iOS中使用锁机制的开销较大,会损耗性能。
    总之,就是只使用nonatomic。
    ② readwrite,readonly
    如果忽略这个属性,那么系统默认是readwrite。生成setter和getter两个方法,如果指定了readonly,那么就只生成getter方法,没有setter方法。此属性也相对简单。
    ③ 重点来了
    assign,strong,weak,copy,unsafe_unretained,retain
    先简单粗暴的上结论:
    对于标量类型NSInteger,NSUInteger,CGFloat,NSTimeInterval,使用assign类型。
    对于有对应可变类型子类的对象比如:NSString/NSMutableString,NSArray/NSMutableArray,NSDictionary/NSMutableDictionary等,使用copy来修饰。copy也用来修饰block。
    对于可变类型,一般使用强引用strong来修饰,如NSMutableString,NSMutableArray,NSMutableDictionary
    还有其他必须强持有的对象,也使用strong来修饰。
    weak表示对所赋的值对象持有弱引用表示一种“非拥有关系”(nonowning relationship),对新值不会增加引用计数,也不会减少旧值的引用计数。所赋的值在引用计数为0被销毁后,weak修饰的属性会被自动置为nil能够有效防止野指针错误。
    weak常用在修饰delegate等防止循环引用的场景。
    retain在MRC模式下,与strong相同。
    一些注意点:assign也可以用于修饰NSString,但是由于不计算引用计数,如果属性被置为nil,并不会像weak一样自动销毁,所以如果nil以后再去self.name访问,就会发生野指针错误,程序崩溃。

    相关文章

      网友评论

          本文标题:ios属性知识梳理

          本文链接:https://www.haomeiwen.com/subject/bunedftx.html