本文共 3914 字,大约阅读时间需要 13 分钟。
一、多线程特性
默认:automic **1、automic:原子的,表示线程安全。**使用automic的目的是为了确保其他线程不再同一时间内访问形同的资源。使用工程中不会被线程调度机制打断的操作,原子操作一旦开始,就要一直运行到结束,不会被打断。(ios10之前是自旋锁,ios10之后使用的是互斥锁,编译器会自动生成互斥加锁的代码,避免变量的读写不同步)但往往即使声明了automic属性也不一定保证线程安全,而且这种机制是耗费系统资源的。(所以一般都声明为nonatomic属性) **2、nonatomic:非原子的。表示线程不安全。**可以在不同的地方读取和设置属性的值,(可能会导致读写不同步)编译器会少生成一些互斥加锁的代码,可以提高效率。 总结:涉及到多线程的时候,使用atomic,保证安全。不涉及多线程,使用nonatomic效率会更高。博主建议 所有的属性,都尽可能使用nonatomic,以提高效率,除非真的有必要考虑线程安全。二、读写特性
默认:readwrite **readwrite:**编译器会为属性生成get和set方法 **readonly:**编译器只生成get方法 即,readwrite属性修饰时可读可写,而readonly修饰时只能读取它的属性而能修改。三、访问修饰符(类的实例化权限,也叫继承权限)
1、【缺省】修饰@protected 即受保护的成员变量,1)、父类可以在自己的成员方法中使用,继承于该父类的子类也可以在成员方法中使用。2)、不能在外部函数使用。3)、默认情况下,所有的成员变量都是受保护。 2、@public 即公开的成员变量 1)、父类可以用,子类可以用,外部方法也可以调用。2)、完全没有权限可言,想用就可以用。 注意:不建议使用,极不安全。 3、@private 私有的成员变量 1)、只能在父类的成员方法中使用,继承于该类的子类,没有任何使用权限 2)、在外部也不能使用 四、修饰符的用法介绍 1、copy **1)NSString:**通常都使用copy,以得到新的内存分配,而不只是原来的引用。 通过上面两图你发现了什么,当testStr1用strong修饰时我们只给self.testStr1赋了一次值,但是self.testStr1 的值改变了,这是因为把可变字符的地址指向了testStr1,所以string1的值改变了,self.testStr1也跟着改变,而当用copy时,相当于对string1做了一次深拷贝,两者地址不同,当修改string1的值时,testStr1当然不会变,考虑到数据的安全性,字符串用copy修饰。 2)Block声明用copy 普及: 1.Block分为全局Block、堆Block和栈Block 2.方法是在内存的栈区,每一个方法都是在被调用的时候从硬盘到内存,然后去执行,执行完就消失,所以,方法的内存不需要我们管理。 3.OC中的类对象(在堆区),block默认是在栈区,我们没办法控制他的消亡。 当我们用copy修饰的时候,系统会把该 block的实现拷贝一份到堆区,这样我们对应的属性,就拥有的该block的所有权。就可以保证block代码块不会提前消亡。, 因此如果block中用到self时, 需要将其弱化, 通过__weak或者__unsafe_unretained. 2、strong和weak、assign weak 不增加引用计数,也不持有对象,ARC时才会使用,ARC模式下会使用,相当于assign,对象废弃可以把对应的指针变量置为nil的状态。只可以修饰对象,如果修饰基本数据类型,编译器会报错。 weak比assign多了一个功能,当对象消失后自动把指针变成nil,好处不言而喻。 runtime如何实现weak变量的自动置nil Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,key是所指对象的地址,value是weak指针的地址(这个地址的值是所指对象的地址)数组。 weak 的实现原理可以概括一下三步: 1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。 2、添加引用时:objc_initWeak函数会调用objc_storeWeak() 函数,objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。 3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。 assign 修饰基本数据类型:基本数据类型是分配在栈上的,由系统分配和释放,所以不会造成野指针。 修饰对象:如果用assign修饰对象,当对象被释放后,指针的地址还是存在的,也就是说指针并没有被置为nil,从而造成了野指针。因为对象是分配在堆上的,堆上的内存由程序员分配释放。而因为指针没有被置为nil,如果后续的内存分配中,刚好分配到了这块内存,就会造成崩溃。strong与week
strong与weak是由ARC新引入的对象变量属性,ARC引入了新的对象的生命周期限定,即零弱引用。如果零弱引用指向的对象被deallocated的话,零弱引用的对象会被自动设置为nil。即一旦最后一个指向该对象的strong类型的指针离开,这个对象将被释放,如果这个时候还有weak指针指向该对象,则会清除掉所有剩余的weak指针。 强引用与弱引用的广义区别: 强引用也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示列表中,则此对象会被从内存中释放。 弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个若引用,只要没有强引用指向他,那么其还是会被清除。 简单讲,strong等同retain,weak比assign多了一个功能,当对象消失后自动把指针变成nil。 strong:对于继承于NSObject类型的对象,若要声明为强使用,使用strong,若要使用弱引用,使用__weak来引用,用于解决循环强引用的问题。1)对于xib上的控件引用,使用weak
当我们用xib拉一个控件的时候,系统会默认使用weak修饰,这是应为,在连接时因为这个label已经放到view上了,label的引用计数为1,因此只要这个View不被释放,这个label的引用计数都不会为0,因此这里使用weak引用。
如果我们不使用xib/storyboard,而是使用纯代码创建仍然用weak修饰
@property (nonatomic, weak) UILabel *label; 由于label在创建时,没有任何强引用,因此就有可能提前释放。所以只要我们在创建以后需要使用它,我们必须保证至少有一个强引用,否则引用计数为0,就会被释放掉。得出结论:使用纯代码时控件需要用strong修饰。 2)代理用weak修饰 我们这里举一个例子建立一个Person类和一个Pig类,Pig类中有一个PigDelegate协议 weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制strong:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用(Retain Cycles)
代码逻辑如下: 建立一个Pig类 pig.h文件pig.m文件
然后建立一个Person类 Person.h文件Person.m文件
在ViewController中
结果
1)当代理用weak修饰时,运行程序后在控制台会打印: 说明两者都被正常释放销毁 2)当代理用strong修饰时,运行程序后在控制台打印内容为空 说明没有走到两者的delloc方法中,两者并没有释放销毁,就造成了内存泄漏。 3、__weak 用于解决Block引起的循环引用 举例:某对象self,有strong类型的成员变量blockA,blockA内部引用了self,如果self不经过__weak处理,就会变成:self强引用blockA,blockA强引用self,这就是循环引用。 使用用法: __weak typeof(self) weakSelf = self; 就可以直接使用weakSelf代替self了,当self释放时,weakSelf已经等于nil。 4、__block Blocks可以访问局部变量,但是不能修改如果修改局部变量,需要加__block 本图说明在block里面修改tempNum的值系统会报错。 但如果对tempNum加上__Block则不会报错 5、__strong: 对于变量的声明,如果要使用强引用,可以使用strong,默认就是strong,因此不写与写__strong声明都是一样的。 6、unsafe_unretained: 这个是比较少用的,几乎没有使用到。在所引用的对象被释放后,该指针就成了野指针,不好控制。 7、_unsafeunretained: 也是很少使用。同上。 8、assign 不会使引用计数加1,直接赋值,可修饰对象,和基本数据类型。转载地址:http://pwcti.baihongyu.com/