• 黑马程序员-内存管理之autorelease和ARC机制


    一.autorelease

      之前我们都是手动release对象,但是有时候我们需要延迟release对象,这里我们就需要用到autorelease,系统会把当前对象放在当前的autorelease pool中,当autorelease pool销毁时,会把当前池子中的所有对象做一次release操作。对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这些池子都是以栈结构的形式存在,在每一个Runloop结束时,当前栈顶的池子会被销毁,所有对象做一次release操作

    1.autorelease的基本用法
    1> 会将对象放到一个自动释放池中
    2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
    3> 会返回对象本身
    4> 调用完autorelease方法后,对象的计数器不变

    2.autorelease的好处
    1> 不用再关心对象释放的时间
    2> 不用再关心什么时候调用release

    3.autorelease的使用注意
    1> 占用内存较大的对象不要随便使用autorelease
    2> 占用内存较小的对象使用autorelease,没有太大影响


    4.错误写法
    1> alloc之后调用了autorelease,又调用release
    @autoreleasepool
    {
    // 1
    Person *p = [[[Person alloc] init] autorelease];

    // 0
    [p release];
    }

    2> 连续调用多次autorelease
    @autoreleasepool
    {
    Person *p = [[[[Person alloc] init] autorelease] autorelease];
    }

    5.自动释放池
    1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
    2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池


    6.自动释放池的创建方式
    1> iOS 5.0前
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [pool release]; // [pool drain];

    2> iOS 5.0 开始
    @autoreleasepool
    {

    }
    下面是示例代码:

     1 #import <Foundation/Foundation.h>
     2 
     3 @interface Person : NSObject
     4 @property (nonatomic, assign) int age;
     5 
     6 + (id)person;
     7 
     8 + (id)personWithAge:(int)age;
     9 
    10 @end
     1 #import "Person.h"
     2 
     3 @implementation Person
     4 
     5 + (id)person
     6 {
     7     return [[[self alloc] init] autorelease];
     8 }
     9 
    10 + (id)personWithAge:(int)age
    11 {
    12     Person *p = [self person];
    13     p.age = age;
    14     return p;
    15 }
    16 
    17 - (void)dealloc
    18 {
    19     NSLog(@"%d岁的人被销毁了", _age);
    20     
    21     [super dealloc];
    22 }
    23 @end
    1 #import "Person.h"
    2 
    3 @interface GoodPerson : Person
    4 
    5 @property (nonatomic, assign) int money;
    6 
    7 @end
    #import "GoodPerson.h"
    
    @implementation GoodPerson
    
    @end
     1 #import <Foundation/Foundation.h>
     2 #import "Person.h"
     3 #import "GoodPerson.h"
     4 
     5 int main()
     6 {
     7     @autoreleasepool {
     8         Person *p = [Person personWithAge:100];
     9         
    10         
    11         GoodPerson *p2 = [GoodPerson personWithAge:10];
    12         
    13         p2.money = 100;
    14     }
    15     return 0;
    16 }

    注意问题:

    1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的,例如以下2个例子。

    NSString *str = @"123123";
    NSString *str2 = [NSString stringWithFormat:@"age is %d", 10];


    下面调用了对象方法,需要release操作
    NSNumber *num = [[NSNumber alloc] initWithInt:10];

    [num release];

    2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
    1> 创建对象时不要直接用类名,一般用self
    + (id)person
    {
      return [[[self alloc] init] autorelease];
    }

    二.ARC机制

    ARC机制是IOS5所引入的,英文全称Automatic Reference Counting,自动引用计数,即ARC。有了ARC我们就不需要来手动操作内存管理的引用计数了,像retain,relesase,autorelease关键字都禁止使用。ARC全程帮我们管理内存,少了很多代码,也不用担心内存泄露。

    ARC的特点:

    1.ARC特点
    1> 不允许调用release、retain、retainCount、autorelease
    2> 允许重写dealloc,但是不允许调用[super dealloc]
    3> @property的参数
    * strong :成员变量是强指针(适用于OC对象类型)
    * weak :成员变量是弱指针(适用于OC对象类型)
    * assign : 适用于非OC对象类型
    4> 以前的retain改为用strong

    2.ARC的判断准则:只要没有强指针指向对象,就会释放对象。

    下面代码是不使用ARC和使用ARC的区别。

    创建一个Person类。

    非ARC

     1 #import <Foundation/Foundation.h>
     2 
     3 @class Dog;
     4 
     5 @interface Person : NSObject
     6 
     7 @property (nonatomic, retain) Dog *dog;
     8 
     9 @property (nonatomic, retain) NSString *name;
    10 
    11 @property (nonatomic, assign) int age;
    12 
    13 @end
     1 #import "Person.h"
     2 
     3 @implementation Person
     4 
     5 - (void)dealloc
     6 {
     7     NSLog(@"Person is dealloc");
     8 
     9     [_dog release];
    10     [_name release];
    11     
    12     [super dealloc];
    13 }
    14 
    15 @end
     1 #import <Foundation/Foundation.h>
     2 #import "Person.h"
     3 #import "Dog.h"
     4 
     5 int main()
     6 {
     7     Dog *d = [[Dog alloc] init];
     8     Person *p = [[Person alloc] init];
     9     p.dog = d;
    10     [p release];
    11     [d release];
    12     
    13     return 0;
    14 }

    使用ARC后代码变成了如下:

     1 #import <Foundation/Foundation.h>
     2 
     3 @class Dog;
     4 
     5 @interface Person : NSObject
     6 
     7 @property (nonatomic, strong) Dog *dog;
     8 
     9 @property (nonatomic, strong) NSString *name;
    10 
    11 @property (nonatomic, assign) int age;
    12 
    13 @end
     1 #import "Person.h"
     2 
     3 @implementation Person
     4 
     5 // 如果要重写dealloc,禁止写最后的[super dealloc];
     6 - (void)dealloc
     7 {
     8     NSLog(@"Person is dealloc");
     9     
    10     // [super dealloc];
    11 }
    12 
    13 @end
     1 #import <Foundation/Foundation.h>
     2 #import "Person.h"
     3 #import "Dog.h"
     4 
     5 int main()
     6 {
     7     Dog *d = [[Dog alloc] init];
     8     Person *p = [[Person alloc] init];
     9     p.dog = d;
    10 
    11     return 0;
    12 }

    很明显的变化就是使用了ARC机制后禁止调用release、retain、retainCount、autorelease关键字,原来的retain用strong来代替,重写dealloc方法时禁止调用[super dealloc]

  • 相关阅读:
    Gitlab 与 Git Windows 客户端一起使用的入门流程
    怎样把SEL放进NSArray里
    PerformSelector may cause a leak because its selector is unknown 解决方法
    drawRect
    记录常规越狱的判断方法
    网页 js
    UICollectionView 基础
    FMDB的简单使用
    图层的一些基本动画效果
    NSPredicate简单介绍
  • 原文地址:https://www.cnblogs.com/pangjiayang/p/4006117.html
Copyright © 2020-2023  润新知