Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/102.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 将对象直接指定给特性时,为什么圆弧不能正常工作_Ios_Objective C_Automatic Ref Counting - Fatal编程技术网

Ios 将对象直接指定给特性时,为什么圆弧不能正常工作

Ios 将对象直接指定给特性时,为什么圆弧不能正常工作,ios,objective-c,automatic-ref-counting,Ios,Objective C,Automatic Ref Counting,我有这两件东西 //Header file #import <Foundation/Foundation.h> @class Object2; @interface Object1 : NSObject @property Object2 *child; @end @interface Object2 : NSObject @property (weak) Object1 *parent; @end // Implementation File #import "MyC

我有这两件东西

//Header file
#import <Foundation/Foundation.h>

@class Object2;

@interface Object1 : NSObject
@property Object2 *child;

@end

@interface Object2 : NSObject

@property (weak) Object1 *parent;

@end

// Implementation File
#import "MyClass.h"

@implementation Object1

-(void)dealloc{
    NSLog(@"deallocating parent");
}

@end

@implementation Object2

-(void)dealloc{
    NSLog(@"deallocating child");
}

@end
在打印“完成”之前,孩子似乎不会被释放

但是,如果我使用一个中间变量来保存子对象,解除分配似乎会发生

@autoreleasepool {
    Object1 *p1 = [[Object1 alloc]init];
    Object2 *c1 = [[Object2 alloc]init];
    p1.child = c1;

    c1.parent = p1;
    c1 = nil;

    NSLog(@"Setting p1 to nil");
    p1=nil;
    NSLog(@"Done");


}
我很好奇为什么会发生这种情况。

问题在于:

p2.child=[[Object2 alloc]init]

创建一个“retain/autorelease”对象,并调用setter,然后setter将保留该对象,因此该对象将在autorelease池关闭时取消分配。编译器不够聪明,无法优化自动释放

在某种程度上,ARC将您的代码编译为与MRR等效的代码:

p2.child=[[Object2 alloc]init]autorelease]

当你写作时:

Object2*c1=[[Object2 alloc]init]

编译器足够聪明,可以在调用
c1=nil
时优化自动释放并使其成为一个简单的释放

ARC将您的代码编译为与MRR等效的代码:

Object2*c1=[[Object2 alloc]init];
...
[c1释放];
c1=零;

作为旁注,对象总是正确地取消分配,它只是在末尾取消分配
@autoreleasepool

2014-07-11 13:18:03.233测试弱[48241:303]将p1设置为零
2014-07-11 13:18:03.235测试弱[48241:303]解除分配母公司
2014-07-11 13:18:03.235测试弱[48241:303]完成
2014-07-11 13:18:03.236测试弱[48241:303]解除分配孩子

问题在于:

p2.child=[[Object2 alloc]init]

创建一个“retain/autorelease”对象,并调用setter,然后setter将保留该对象,因此该对象将在autorelease池关闭时取消分配。编译器不够聪明,无法优化自动释放

在某种程度上,ARC将您的代码编译为与MRR等效的代码:

p2.child=[[Object2 alloc]init]autorelease]

当你写作时:

Object2*c1=[[Object2 alloc]init]

编译器足够聪明,可以在调用
c1=nil
时优化自动释放并使其成为一个简单的释放

ARC将您的代码编译为与MRR等效的代码:

Object2*c1=[[Object2 alloc]init];
...
[c1释放];
c1=零;

作为旁注,对象总是正确地取消分配,它只是在末尾取消分配
@autoreleasepool

2014-07-11 13:18:03.233测试弱[48241:303]将p1设置为零
2014-07-11 13:18:03.235测试弱[48241:303]解除分配母公司
2014-07-11 13:18:03.235测试弱[48241:303]完成
2014-07-11 13:18:03.236测试弱[48241:303]解除分配孩子

这里有很多东西,这是一个很好的例子。首先要意识到的是,dealloc并不是在程序结束时发生的。它发生在自动释放池的末尾(正如Julien所指出的)。ObjC在程序终止时不运行
dealloc
。如果您将“完成”行移到autoreleasepool之外,就会看到这一点。要理解的第二件大事是,这与ARC无关。与MRC的行为相同

那么,为什么与中间产品有区别呢?嗯,你需要想想这句话的意思:

p2.child.parent = p2;
这真的是:

[[p2 child] setParent:p2];
这相当于:

id temp = [p2 child];
[temp setParent:p2];
在另一个示例中,对
[p2-child]
的调用从未发生过(它调用
[p2-setChild://code>,这是完全不同的)

您已经使用了
子对象的默认属性设置。默认设置包括原子设置。这意味着我们的getter看起来像:

- (Object2 *)child {
  return [[_child retain] autorelease];
}
(这稍微复杂一点,因为它还与setter同步,但这与本次讨论无关。)

因此,现在我们有一个自动释放的
temp
,它将在自动释放池的末尾被清理。如果将
(非原子)
添加到属性定义中,您将看到该行为符合您的期望

您的另一个示例从未调用过
[p2 child]
,因此它不会对其添加额外的retain/autorelease,因此它会更快地被释放

这里的一个教训是,在大多数情况下,
非原子的
是首选。有点令人惊讶的是,
atomic
被设为默认值,许多Cocoa开发人员几乎只使用
nonatomic
(大多数苹果示例代码也是如此)。额外的retain/autorelease的思想是,它在多线程代码中提供了一些保护(没有它,您的局部变量可能会在使用它之前解除分配)。实际上,通常有比
atomic
更好的方法来实现这一点(而且
atomic
本身并不能提供实际的线程安全性)。也就是说,使用
原子属性
不是问题,上面的代码没有错误;它只需要多一点内存,就可以维持更长的时间


如果您对这些事情感到好奇,我总是建议您查看一下程序集输出。这可能有点难读,但您通常可以了解到编译器选择做什么。在助手窗格中,只需选择“Assembly”(从具有“对应项”的同一菜单中选择)。

这里有很多事情要做,这是一个很好的示例。首先要意识到的是,dealloc并不是在程序结束时发生的。它发生在自动释放池的末尾(正如Julien所指出的)。ObjC在程序终止时不运行
dealloc
。如果您将“完成”行移到autoreleasepool之外,就会看到这一点。要理解的第二件大事是,这与ARC无关。与MRC的行为相同

那么,为什么与中间产品有区别呢?嗯,你需要想想这句话的意思:

p2.child.parent = p2;
这真的是:

[[p2 child] setParent:p2];
这相当于:

id temp = [p2 child];
[temp setParent:p2];
<