一:@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。 |
开发过程当中,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
由于父类指针能够指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 不管给我传入是一个可变对象仍是不可对象,我自己持有的就是一个不可变的副本.
若是咱们使用是 strong,那么这个属性就有可能指向一个可变对象,若是这个可变对象在外部被修改了,那么会影响该属性
c:深浅copy
七:block中copy
我的理解:默认状况下,block会存档在栈中(栈是吃了吐),因此block会在函数调用结束被销毁,在调用会报空指针异常,若是用copy修饰的话,可使其保存在堆区(堆是吃了拉) ,它的生命周期会随着对象的销毁而结束的。只要对象不销毁,咱们就能够调用在堆中的block。
在了解block为何要用copy以前,咱们要先了解block的三种类型
一 NSGlobalBlock:全局的静态block 没有访问外部变量 你的block类型就是这种类型(也就是说你的block没有调用其余外部变量)
二 NSStackBlock:保存在栈中的block,没有用copy去修饰而且访问了外部变量,你的block类型就是这种类型,会在函数调用结束被销毁 (须要在MRC)
三 NSMallocBlock 保存在堆中的block 此类型blcok是用copy修饰出来的block 它会随着对象的销毁而销毁,只要对象不销毁,咱们就能够调用的到在堆中的block。
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.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。
6: MRC使用了retain修饰的block崩溃掉了,当将MRC切换回ARC,而且把修饰符换为strong时,并无发生崩溃,说明该block被推入了堆,拥有了保存外部变量内存的能力。