iOS开发知识

《iOS高级编程》中的ARC

2019-07-15  本文已影响0人  太阳骑士索拉尔

关于我的仓库

前言

准备工作

内存管理四大原则

  1. 自己生成的对象,自己持有
  2. 非自己生成的对象,自己也能持有
  3. 不再需要自己持有的对象时释放
  4. 非自己持有的对象无法释放

ARC规则(p.29 ~ p.65)

__strong修饰符

id obj = [[NSObject alloc] init];
//id __strong obj = [[NSObject alloc] init];
NSObject *obj = [[NSObject alloc] init];
//NSObject __strong *obj = [[NSObject alloc] init];

补充知识:id的本质

超出变量作用域 = 废弃

__strong对象相互赋值

语句 obj0 obj1 obj2
id __strong obj0 = [[NSObject alloc] init];//生成对象A A
id __strong obj1 = [[NSObject alloc] init];//生成对象B A B
id __strong obj2 = nil; A B nil
obj0 = obj1;//obj0强引用对象B;而对象A不再被ojb0引用,被废弃 B B nil
obj2 = obj0;//obj2强引用对象B(现在obj0,ojb1,obj2都强引用对象B) B B B
obj1 = nil;//obj1不再强引用对象B B nil B
obj0 = nil;//obj0不再强引用对象B nil nil B
obj2 = nil;//obj2不再强引用对象B,不再有任何强引用引用对象B,对象B被废弃 nil nil nil

方法参数中使用__strong

__strong导致的循环引用

补充知识:内存泄漏

赋值阶段

语句 test0 test0.obj test1 test1.obj
id test0 = [[Test alloc] init];//生成TestA TestA
id test1 = [[Test alloc] init];//生成TestB TestA TestB
[test0 setObject:test1]; TestA TestB TestB TestA
[test1 setObject:test0]; TestA TestB TestB TestA

失效阶段

What happen TestA引用计数 TestA持有者 TestB引用计数 TestB持有者
初始状态 2 test0,test1.obj 2 test0.obj,test1
test0超出作用域 1 test1.obj 2 test0.obj,test1
test1超出作用域 1 test1.obj 1 test0.obj

为什么test0失效的时候,obj_依然存在

造成结果

我要dealloc TestA
我要dealloc TestB

对自身的强引用

__weak修饰符

生成__weak的持有者

id __weak obj = [[NSObject alloc] init];
//这里如果直接使用__weak obj来持有对象,由于这里是弱引用,引用计数不会加一,对象随时可能会被dealloc
//后面会讲到,其实内部是用__autoreleasing来维持该对象不被dealloc

id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
//在这里,obj0先强持有该对象,给它引用计数+1,防止其dealloc
//之后再让obj1去弱持有该对象,达成我们需要的目的

使用__weak的好处

__autoreleasing修饰符

与MRC时比较

64149CAE-5DF0-44CC-9E67-3A10081A9DC3

自动调用

weak修饰符与autoreleasing修饰符

id  __weak obj1 = obj0;
NSLog(@"class = %@",[obj1 class]);

id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class = %@",[tmp class]);//实际访问的是注册到自动释放池的对象

autoreleasing修饰符无处不在

牢记:只有作为alloc/new/copy/mutableCopy方法的返回值而渠道对象时,能够自己生成并持有对象,其他情况都是"取得非自己生成并持有的对象",换句话说,就轮到我们的autoreleasing修饰符上场了

具体ARC规则

规则

dealloc

- (void)dealloc  
{  
    [[NSNotificationCenter defaultCenter] removeObserver:self];//移除通知观察者  
    [[XMPPManager sharedManager] removeFromDelegateQueue:self];//移除委托引用  
  [ [MyClass shareInstance]  doSomething ]//其他操作  
     
}  

__bridge

属性声明与所有权修饰符

D1980B5B-D29C-4B3B-8FC0-121567F38F0C

ARC实现(p.65 ~ p.78)

说明

C10E595E-A479-433F-AE43-9920A37275D1

__strong修饰符实现

//自己持有
{
    id __strong obj = [NSObject alloc] init];//obj持有对象
}

id obj = objc_mesgSend(NSObject, @selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);//超出作用域,释放对象

//非自己持有
{
    id __strong obj = [NSMutableArray array];
}

id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);//objc_retainAutoreleasedReturnValue的作用:持有对象,将对象注册到autoreleasepool并返回。
objc_release(obj);

+ (id)array
{
   return [[NSMutableArray alloc] init];
}

+ (id)array
{
   id obj = objc_msgSend(NSMutableArray, @selector(alloc));
   objc_msgSend(obj,, @selector(init));
   return objc_autoreleaseReturnValue(obj);//objc_autoreleaseReturnValue:返回注册到autoreleasepool的对象。
}

objc_retainAutoreleasedReturnValue与objc_autoreleaseReturnValue

两个不一定

解释

__weak修饰符实现

objc_storeWeak

注册到autoreleasepool

id obj1;
objc_initWeak(&obj1,obj);//初始化附有__weak的变量
id tmp = objc_loadWeakRetained(&obj1);//取出附有__weak修饰符变量所引用的对象并retain
objc_autorelease(tmp);//将对象注册到autoreleasepool中
objc_destroyWeak(&obj1);//释放附有__weak的变量

__autoreleasing修饰符实现

id pool = objc_autoreleasePoolPush();//pool入栈
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);//pool出栈

2019.7.22 更新:关于weak修饰符的一些打印实验

//在ARC中我们可以使用__bridge来查看应用计数

NSObject *obj0 = [[NSObject alloc] init];
        printf("retain count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj0))); 
        NSObject * __weak obj1 = obj0;
        printf("retain count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj1)));
        printf("retain count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj0)));
        
//        retain count = 1
//        retain count = 2
//        retain count = 1
id  __weak obj1 = obj0;
NSLog(@"class = %@",[obj1 class]);

id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class = %@",[tmp class]);//实际访问的是注册到自动释放池的对象

2019.7.25晚 更新:《Effective Objective-C 2.0》中的ARC

p.121 stringValue

+ (NSString *)stringValue {
  NSString *str = [[NSString alloc] initWithFormat:@"I am this:%@", self];
  return str;
}

NSString *str1 = [NSString stringValue];
NSString *str = [NSString alloc] initWithFormat:@"I am this:%@", self];
NSString *str1 = str;//str1就是接收者,使得该对象又被retain了一次

p.124 三个演示ARC的例子

  1. 这个方法以"new"开头,既然"person"已经使得引用计数+1了【因为alloc】,那么我们不需要做任何操作了,直接返回就行;也就是说,以alloc开头的方法,只要保证返回的对象引用计数+1了就行
  2. 该方法不是以那几个开头,因此返回时自动autorelease
  3. personOne没有注册到pool中,因此超出作用域直接release;personTwo相反

objc_retainAutoreleasedReturnValue与objc_autoreleaseReturnValue

理解

疑惑

打印试验

#import "ViewController.h"

__weak id autoObj;
id stongObj;

@interface ViewController ()


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    id __autoreleasing obj = [NSMutableArray arrayWithObject:@"123"];
    
    //NSLog(@"%@", obj);
    autoObj = obj;
    NSLog(@"1obj:%@", autoObj);
    
    
}


- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"2obj:%@", autoObj);
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"3obj:%@", autoObj);
}

@end

2019.7.26更新 至是疑始释

关于autorelease

+ (NSString *)stringValue {
  NSString *str = [NSString alloc] initWithFormat:@"I am this:%@", self];
  return str;
}

NSString *str1 = [NSString stringValue];

疑点

上一篇下一篇

猜你喜欢

热点阅读