01 (OC)* @property 后面能够有哪些修饰符?

一:@property 后面能够有哪些修饰符?c++

1:线程安全的:面试

     atomic,nonatomic数组

2:访问权限的安全

     readonly,readwrite多线程

3:内存管理(ARC)并发

       assign, copy, strong,weak,函数

4: 内存管理(MRC)性能

    assign,retain,copy学习

 

ARC 下,不显式指定任何属性关键字时,默认的关键字都有哪些?atom

基本数据: atomic,readwrite,assign

普通的 OC 对象: atomic,readwrite,strong

 

readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak属性的做用分别是什么。 

关键字 注释
readwrite 此标记说明属性会被当成读写的,这也是默认属性。
readonly 此标记说明属性只能够读,也就是不能设置,能够获取。
assign 不会使引用计数加1,也就是直接赋值。
retain 会使引用计数加1。
copy 创建一个索引计数为1的对象,在赋值时使用传入值的一份拷贝。
nonatomic 非原子性访问,多线程并发访问会提升性能。
atomic 原子性访问。
strong 打开ARC时才会使用,至关于retain。
weak 打开ARC时才会使用,至关于assign,能够把对应的指针变量置为nil。



 
 
 
 

 

 

 

 

 

 

 

 

三:1:原子性:非原子性

 开发过程当中,setter和getter方法到处都在使用,若是使用atomic修饰,setter和getter方法内部会作不少多线程安全的操做,会很占用系统资源,下降系统性能。

因此在日常开发中原子性(线程安全)通常设置为nonatomic,只有在须要安全的地方atomic

 说atomic与nonatomic的本质区别其实也就是在setter方法上的操做不一样:

nonatomic的实现:
- (void)setCurrentImage:(UIImage *)currentImage
{
    if (_currentImage != currentImage) {
        [_currentImage release];
        _currentImage = [currentImage retain];
            
        // do something
    }
}
- (UIImage *)currentImage
{
    return _currentImage;
}

atomic的实现:
- (void)setCurrentImage:(UIImage *)currentImage
{
    @synchronized(self) {
        if (_currentImage != currentImage) {
            [_currentImage release];
            _currentImage = [currentImage retain];
                    
            // do something
        }
    }
}

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

 

四:读写访问权限

读写性的控制(readonly,readwrite,setter,getter)

readonly:只读属性,告诉编译器之声明getter方法,而没有setter(只能读取值,不能被赋值)

readwrite:读写属性,告诉编译器,既声明setter又声明getter方法,readwrite是属性读写性控制的默认修饰词

 

五:内存权限。

1:weak和assign的区别-正确使用weak、assign 

不多有人知道weak表实际上是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址数组。更多人的人只是知道weak是弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil。一般用于解决循环引用问题。但如今单知道这些已经不足以应对面试了,好多公司会问weak的原理。weak的原理是什么呢?下面就分析一下weak的工做原理(只是本身对这个问题好奇,学习过程当中的笔记,但愿对读者也有所帮助)。

 

weak 实现原理的归纳

Runtime维护了一个weak表,用于存储指向某个对象的全部weak指针。weak表实际上是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。

 weak 的实现原理能够归纳一下三步:

 一、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

 二、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的做用是更新指针指向,建立对应的弱引用表。

三、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取全部weak指针地址的数组,而后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

 

六:区别 

6.1:区别

a.修饰变量类型的区别

weak 只能够修饰对象。若是修饰基本数据类型,编译器会报错-“Property with ‘weak’ attribute must be of object type”。

assign 可修饰对象,和基本数据类型。当须要修饰对象类型时,MRC时代使用unsafe_unretained。固然,unsafe_unretained也可能产生野指针,因此它名字是"unsafe_”。

 

b.是否产生野指针的区别

weak 不会产生野指针问题。由于weak修饰的对象释放后(引用计数器值为0),指针会自动被置nil,以后再向该对象发消息也不会崩溃。 weak是安全的。

assign 若是修饰对象,会产生野指针问题;若是修饰基本数据类型则是安全的。修饰的对象释放后,指针不会自动被置空,此时向对象发消息会崩溃。

 

c、类似

均可以修饰对象类型,可是assign修饰对象会存在问题。

 

d、总结

assign 适用于基本数据类型如int,float,struct等值类型,不适用于引用类型。由于值类型会被放入栈中,遵循先进后出原则,由系统负责管理栈内存。而引用类型会被放入堆中,须要咱们本身手动管理内存或经过ARC管理。

weak 适用于delegate和block等引用类型,不会致使野指针问题,也不会循环引用,很是安全。

 

6.2:copy

a:  怎么用 copy 关键字

NSString、NSArray、NSDictionary 等等常用 copy 关键字,是由于他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary.为确保对象中的属性值不会无心间变更,应该在设置新属性值时拷贝一份,保护其封装性.

block,也常用 copy,关键字block。

使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 能够把它放到堆区.

在 ARC 中写不写都行:对于 block 使用 copy 仍是 strong 效果是同样的,可是建议写上 copy,由于这样显示告知调用者“编译器会自动对 block 进行了 copy 操做。

b、用@property 声明的 NSString(或 NSArray,NSDictionary)常用 copy 关键字,为何?若是改用 strong 关键字,可能形成什么问题?

由于父类指针能够指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 不管给我传入是一个可变对象仍是不可对象,我自己持有的就是一个不可变的副本.
若是咱们使用是 strong,那么这个属性就有可能指向一个可变对象,若是这个可变对象在外部被修改了,那么会影响该属性

c:深浅copy

七:block中copy

1:下面进入主题为何要用copy去修饰block呢

我的理解:默认状况下,block会存档在栈中(栈是吃了吐),因此block会在函数调用结束被销毁,在调用会报空指针异常,若是用copy修饰的话,可使其保存在堆区(堆是吃了拉) ,它的生命周期会随着对象的销毁而结束的。只要对象不销毁,咱们就能够调用在堆中的block。

在了解block为何要用copy以前,咱们要先了解block的三种类型
NSGlobalBlock:全局的静态block 没有访问外部变量 你的block类型就是这种类型(也就是说你的block没有调用其余外部变量)
NSStackBlock:保存在栈中的block,没有用copy去修饰而且访问了外部变量,你的block类型就是这种类型,会在函数调用结束被销毁 (须要在MRC)
NSMallocBlock 保存在堆中的block 此类型blcok是用copy修饰出来的block 它会随着对象的销毁而销毁,只要对象不销毁,咱们就能够调用的到在堆中的block。

2:

2.1:首先,咱们要明确一点,为何要用copy修饰,这是由于在MRC时期,做为全局变量的block在初始化时是被存放在静态区的,这样在使用时若是block内有调用外部变量,那么block没法保留其内存,在初始化的做用域内使用并不会有什么影响,但一但出了block的初始化做用域,就会引发崩溃,使用copy能够将block的内存推入堆中,这样让其拥有保存调用的外部变量的内存的能力。

2.2:(将block存入堆区带来的一个问题,self会持有block的引用,那么在block里使用self会致使循环引用,这也是为何在MRC和ARC时期要分别用__block和__weak来修饰self的缘由)

既然使用copy的缘由是为了让Block在初始化做用域外进行正常访问外部变量,那咱们就来看使用strong能不能达到这种效果。

 

3:外部使用了weakSelf,里面使用strongSelf却不会形成循环,究其缘由就是由于weakSelf是block截获的属性,而strongSelf是一个局部变量会在“函数”执行完释放。

     是为了保证block执行完毕以前self不会被释放,执行完毕的时候再释放。这时候会发现为何在block外边使用了__weak修饰self,里面使用__strong修饰weakSelf的时候不会发生循环引用?!

 

 4:__block和__weak的区别 2:

4.1:__weak 自己是能够避免循环引用的问题的,可是其会致使外部对象释放了以后,block 内部也访问不到这个对象的问题,咱们能够经过在 block 内部声明一个 __strong 的变量来指向 weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题。

 

4.2:__block 自己没法避免循环引用的问题,可是咱们能够经过在 block 内部手动把 blockObj 赋值为 nil 的方式来避免循环引用的问题。

另一点就是 __block 修饰的变量在 block 内外都是惟一的,要注意这个特性可能带来的隐患。可是__block有一点:这只是限制在ARC环境下。在非arc下,__block是能够避免引用循环的/

 

4.3:另外,MRC中__block是不会引发retain;但在ARC中__block则会引发retain。因此ARC中应该使用__weak。

 

5:为何使用weakSelf

    经过 clang -rewrite-objc 源代码文件名 将代码转为c++代码(实质是c代码),能够看到block是一个结构体,它会将全局变量(self)保存为一个属性(是__strong的),而self强引用了block这会形成循环 引用。因此须要使用__weak修饰的weakSelf。

为何在block里面须要使用strongSelf

6:  MRC使用了retain修饰的block崩溃掉了,当将MRC切换回ARC,而且把修饰符换为strong时,并无发生崩溃,说明该block被推入了堆,拥有了保存外部变量内存的能力。

 

 
7:MRC和ARC下的block
  • 若是是ARC(自动)在堆区 NSMallocBlock
  • 若是是MRC(手动)在栈区 NSStackBlock

8:__block修饰变量在block内部改变其变量值的原理

Block不容许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。__block 所起到的做用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也能够修改外部变量的值。

 

9:不过在声明Block时,使用strongretain会有大相径庭的效果。strong会等于copy,而retain居然等于assign

 

10:【在ARC下】:彷佛已经没有栈上的block了,要么是全局的,要么是堆上的。有一个特殊状况:若是仅仅定义了block没有赋值给变量的话,还是在栈上,

 

【在非ARC下】:存在这栈、全局、堆这三种形式。 

相关文章
相关标签/搜索