ios开发基础学习笔记(十四)--ARC

前言

大家好,我是milo,前面对那么多关于MRC的知识做了总结,今天终于过渡到ARC来了,其实学习就是深入浅出,懂得更多基础,能够让你在开发中都做到心中有数,不至于盲目,共勉。

ARC简介

ARC是ios5.0之后增加的新特性,全称Automatic Reference Counting(自动引用计数),不同于MRC手动管理内存的方式,ARC会让编译器会自动在适当的地方插入适当的retain、release、autorelease语句,也就是说不需要程序猿手动进行内存管理了。而且我们创建文件的时候默认都是使用ARC的。

ARC的使用演示

什么使用?根本就不需要去想它在哪好吗?它是编译器的特性,我们写代码时它会自动暗中帮我们补全的,请看下面代码示例:

JJPerson.m里重写一下dealloc方法

为了观察对象是否被释放重写dealloc方法.png

(注意:可重写,不可[super dealloc],ARC的管理方式下,oc对象不能写关于内存的代码)

main.m里写一个对象不写内存管理的代码

int main(int argc, const char * argv[]) {
    JJPerson *person = [[JJPerson alloc] init];
    JJDog *dog = [[JJDog alloc] init];
    [person setDog:dog];
    return 0;
}

打印结果:

2018-06-26 15:09:09.007235+0800 ARC[1353:78888] -[JJPerson dealloc]
2018-06-26 15:09:09.007475+0800 ARC[1353:78888] -[JJDog dealloc]
Program ended with exit code: 0

所以在ARC下,我们不写内存管理的代码,不会引起内存问题(而且ARC也不会让你写的)。

ARC的判断原则

只要还有一个强指针变量指向对象,对象就会保持在内存中

强指针:默认所有的指针都是强指针。只要是有强指针指向一个对象,那么这个对象就不会被释放,如果没有强指针指向一个对象,那么这个对象就被立即回收,用__strong标示,但是因为默认所有指针都是强指针,所以他没有用。

弱指针:弱指针指向的对象不影响对象回收,用__weak标示,ARC中也存在循环引用的问题,所以弱指针常用在循环引用,当出现循环引用的时候,必须要有一端是弱指针。

强指针:

int main(int argc, const char * argv[]) {
    
    __strong JJPerson *person = [[JJPerson alloc] init];
// __strong写不写都是默认__strong的,所以没有用;但__weak就不能乱用了,如果在这里代替__strong,那么刚创建的对象马上就被销毁   
    
    JJDog *dog = [[JJDog alloc] init];  
    [person setDog:dog];
    return 0;
}

强指针的使用比较简单,默认不写就行了;而弱指针则要注意以下两点。

弱指针:
1、出现循环依赖的时候要让一端为weak,这一点和MRC一样,只不过MRC使用的是assign
2、刚创建的对象不能使用weak指针指向它,否则会立即释放,因为没有强指针指向它。比如我们常常会使用weak的方式创建控件,但是我们不能直接让weak指针直接指向对象,而是应该先直接创建出控件,再让指针指向它

ARC的使用细节

ARC中的@property
strong : 用于OC对象, 相当于MRC中的retain
weak : 用于OC对象, 相当于MRC中的assign
assign : 用于基本数据类型, 跟MRC中的assign一样
copy : 一般用于NSString, 跟MRC中的copy一样

不能调用release、retain、autorelease、retainCount

可以重写dealloc,但是不能调用[super dealloc]

ARC的优点

ARC是编译器特性,而不是运行时特性,ARC不是其它语言中的垃圾回收, 有着本质区别。

1、完全消除了手动管理内存的烦琐, 让程序猿更加专注于app的业务
2、基本上能够避免内存泄露
3、有时还能更加快速,因为编译器还可以执行某些优化

----------------------------深究部分-------------------------------

看完前面我们就对ARC有了初步的认识了,它就是编译器偷偷摸摸并且合理地把你的对象内存释放掉了,这个合理的时机就是:

结论:通过alloc、new、copy等方式创建出来的对象是在出了作用域后被销毁;而通过get方法、类方法等非前面所说的方式创建出来的对象都是在出了autoreleasepool后被释放的。
(都要满足没有其他强指针指向对象)

跟MRC很像对吧!所以说ARC就是帮我们做了MRC要做的工作并且进行了优化。

下面代码通过打断点+重写dealloc方法就可以让我们知道对象的释放时间点

int main(int argc, const char * argv[]) {
    
     // {}表示一个作用域
    @autoreleasepool{
        {
            JJPerson *person = [[JJPerson alloc] init];
        }//  在这行person被释放
    }
    
    @autoreleasepool{
        {
            JJPerson *newPerson = [JJPerson person];
        }
    }//  在这行newPerson被释放
    
    return 0;
}

但是作用域归作用域(包括autoreleasepool),它也满足没有强指针指向对象就释放的原则,如果依旧还是有一个强指针指向这个对象,那就算出了作用域也无法被释放,作用域的作用可以理解为对里面的指针做一次release操作

见下面代码:

int main(int argc, const char * argv[]) {
    
     // {}表示一个作用域
    @autoreleasepool{
        JJPerson *person1; //  定义一个在作用域外的指针
        {
            JJPerson *person = [[JJPerson alloc] init];
            person1 = person;//  让外界指针指向对象
        }//  这行对象没有释放,因为还有一个外界指针指向它
    }//  在这行对象被释放,因为外界指针出autoreleasepool这个作用域后被释放
    
    @autoreleasepool{
        {
            JJPerson *newPerson = [JJPerson person];
        }
    }//  在这行newPerson被释放
    
    return 0;
}

深究以后我们就能发现,ARC的内存释放和MRC的内存释放基本都是一样的喔!该用release和autorelease的时机跟我前面分析的MRC都一样的喔!很有意思吧!

你可能感兴趣的:(ios开发基础学习笔记(十四)--ARC)