【iOS开发】——属性关键字

  • @property
  • 原子性
  • atomic和nonatomic
  • 读写权限
  • 引用计数
  • strong与retain
  • assign与weak
  • strong与weak
  • strong与copy



什么是属性关键字,属性关键字是用来干什么的?首先我们在学习iOS的时候,首先要懂得什么是属性关键字,所谓属性关键字就是

对一个属性来说,无非俩个操作,读和取,对应的就是 get 和 set 方法;通俗一点讲,这些关键字是底层约定的一些标签,当你上层对声明的属性加上这些关键字时,底层会根据不同的标签,在 get 和 set 方法中,执行不同的代码。

@property

在类中定义属性时,总会使用到@property进行定义,下面就来说说@property的使用。
在使用过程中,如果需求公开且在其他类中使用时,通常会定义在.h头文件中而如果只是该类自已需要使用,这时则会定义在.m实现文件中。所以我们平时可以看到有的属性定义在.h文件中,有的属性定义在.m文件中,就是这个原因。

使用方法:

@property (参数1, 参数2, 参数3, ...) 参数类型 参数名称

那么属性关键字有哪些呢?

iOS都有哪些属性关键字 ios属性默认关键字_ios

原子性

atomic和nonatomic

atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。

atomic:系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。getter 还是能得到一个完好无损的对象(可以保证数据的完整性),但这个对象在多线程的情况下是不能确定的。
也就是说:
如果线程 A 调了 getter方法,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种 可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性 的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic可并不能保证对象的线程安全。

  • 也就是说:如果有多个线程同时调用setter的话,不会出现某一个线程执行完setter全部语句之前,另一个线程开始执行setter情况,相当于函数头尾加了锁一样,每次只能有一个线程调用对象的setter方法,所以可以保证数据的完整性。
  • atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的。

nonatomic:就没有这个保证了,nonatomic返回你的对象可能就不是完整的value。因此,在多线程的环境下原子操作是非常必要的,否则有可能会引起错误的结果。但仅仅使用atomic并不会使得对象线程安全,我们还要为对象线程添加lock来确保线程的安全

nonatomic的速度要比atomic的快。atomic是Objc使用的一种线程保护技术,这种机制是耗费系统资源的,所以在iPhone这种小型设备上,我们基本上都是使用nonatomic,而对象的线程安全问题则由程序员代码控制。

atomic与nonatomic的本质区别其实也就是在setter方法上的操作不同

atmoic和nonatomic是如何实现setter/getter方法的:

/// nonatomic对象
- (void)setCurrentImage:(UIImage *)currentImage
{
    if (_currentImage != currentImage) {
        [_currentImage release];
        _currentImage = [currentImage retain];
    }
}
- (UIImage *)currentImage
{
    return _currentImage;
}


/// atomic对象
- (void)setCurrentImage:(UIImage *)currentImage
{
    @synchronized(self) {
        if (_currentImage != currentImage) {
            [_currentImage release];
            _currentImage = [currentImage retain];
        }
    }
}

- (UIImage *)currentImage
{
    @synchronized(self) {
        return _currentImage;
    }
}

读写权限

  • readwrite是默认属性,同时产生setter\getter方法
  • readonly只生成getter方法,没有setter方法。

引用计数

strong与retain

  • 这两个都是强引用 ,除了某些情况下不一样,其他情况是通用的
  • 主要区别是在修饰block属性的时候,相信大家都知道要用copy吧,block在创建的时候它的内存是默认分配在栈(stack)上,而不是堆(heap)上,所以他的生命周期会随着函数的结束而结束,当你在该作用域外调用该block时, 程序就会crash,而copy之后会放在堆里面。
  • strong在修饰block的时候就相当于copy,而retain修饰block的时候就相当于assign,这样block会出现提前被释放掉的危险。

assign与weak

  • 两者都是弱引用,assign通常用于础数据类型(NSInteger,CGFloat)和C数据类型(int, float, double, char等)使用,还有代理属性的修饰、xib、storyboard中拖出来属性,基本上来说两者是可以通用的。
  • 只是weak比assign多了一个功能,后者会在引用的对象被释放的时候将该属性置为nil,而前者依然会指向原来的位置,这样就会变成野指针在OC中你给你一个nil对象发送消息不会crash,但是给一个对象发送他不能解析的消息是会crash的,所以总的来说weak要比assign安全一些。像delegate属性建议用weak修饰而不是assign。

strong与weak

一个是强引用一个是弱引用,weak指针主要用于“父-子”关系,父类拥有一个子类的strong指针,因此父类是子类的所有者;但为了阻止所有权循环,子类需要使用weak指针指向父类。主要是用来解决循环引用的问题

strong与copy

  • 相同之处:用于修饰标识拥有关系的对象
  • 不同之处:strong的赋值是多个指针指向同一个地址,而copy的复制就是每次会在内存中复制一份对象,指针指向不同的地址。 所有对于不可变对象我们应该使用copy修饰,为确保对象中的字符串值不会无意变动,应该在设置新属性时拷贝一份

copy又分为深拷贝与浅拷贝:

  • 浅拷贝,就是指只是将对象内存地址多了一个引用,也就是说,拷贝结束之后,两个对象的值不仅相同,而且对象所指的内存地址都是一样的。
  • 深拷贝,拷贝内容,就是指拷贝一个对象的具体内容,拷贝结束之后,两个对象的值虽然是相同的,但是指向的内存地址是不同的。两个对象之间也互不影响,互不干扰。

使用时要注意:

  1. 在平时定义属性的时候,对于NSString、NSArray、NSDictionary类型的属性,我们最好设置为copy类型,这样别人使用我们定义的属性的时候,它不管怎么改动该属性的赋值,都不会影响我们给该属性赋的值。
  2. 同样block作为属性是也用copy。
  3. 不要将copy关键字用到NSMutableString、NSMutableArray、NSMutableDictionary等可变对象上,要用Strong关键字