2

这是上一个问题的后续问题,其中可能包含过多的间接细节。考虑以下代码:

BarViewController.h

#import <UIKit/UIKit.h>
@protocol SomeDelegate
- (void)someCallback; // doesn't matter
@end

@interface BarViewController : UIViewController

@property (weak, nonatomic) id <SomeDelegate> delegate;

@end

BarViewController.m

#import "BarViewController.h"

@interface BarViewController ()

@end

@implementation BarViewController

@end

FooViewController.h

#import <UIKit/UIKit.h>

@interface FooViewController : UIViewController

@end

FooViewController.m

#import "FooViewController.h"
#import "BarViewController.h"

@interface FooViewController () <SomeDelegate>
@end

@implementation FooViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    BarViewController *bar = [[BarViewController alloc] init];
    // does this assignment create a "strong" reference i.e. increase retain count by 1?
    bar.delegate = self;
    // *do some useful stuff with bar.delegate here* //
    bar = nil; // is memory for bar.delegate free'd here,
    // or only after this instance of FooViewController is destroyed?
}

#pragma mark - SomeDelegate
- (void)someCallback {
// doesn't matter
}

@end

想象一下,它FooViewController是某个小型应用程序中的主视图控制器,而那BarViewController只是一些短暂的东西,可能旨在让用户选择几个按钮中的一个。 BarViewController报告通过其代表选择的内容。

在我上面的代码中,当我设置barnilinFooViewController.m时,为 预留的内存会发生什么bar.delegate?一方面,我认为设置barnil可能会导致bar.delegate也设置为被释放对象nil的一部分。bar另一方面,我对weak引用的理解是,只有在没有人强烈指向它时才会释放内存。因此,如果bar.delegate = self创建对delegate(是吗?)的强引用,是否有可能以bar.delegate某种方式仍然持有指向我们的实例的指针FooViewController,即使bar是现在nil?这里有内存泄漏的可能性吗?

编辑:
所以我正在考虑的方式是,UIWindow强烈指向我们的实例FooViewController作为根视图控制器,而我们的 BarViewController 实例将弱指向我们的实例FooViewController作为它的委托。因此,即使我们设置bar = nil, bar.delegateweakly 指向一个对象,该对象仍然至少有一个来自 的强指针UIWindow,所以bar.delegate不能基于“当没有其他人强烈指向它时释放一个弱属性”的前提来释放它?

4

2 回答 2

2

除了这里,你几乎做对了:

另一方面,我对弱引用的理解是,只有在没有人强烈指向它时才会释放内存。因此,如果 bar.delegate = self 创建对委托的强引用(是吗?)

声明的属性weak比您想象的要简单得多。就像assign,除了弧生成的 dealloc 之外,它的类将它设置为 nil。并且, bar.delegate = self; 不会“创建对委托的强引用”,它只是分配一个指向 Foo 实例的指针,当 Bar 被释放时该实例将被清除。

所以这就是发生的事情:

// no bar exists
BarViewController *bar = [[BarViewController alloc] init];

// now a bar exists with only a stack variable referring to it, it will be released
// by arc at the bottom of this method

// YOUR QUESTION: does this assignment create a "strong" reference i.e. increase retain count by 1
bar.delegate = self;

// Answer - No. No change in retain counts.  Bar now has an assigned pointer to the
// Foo instance (self)

// *do some useful stuff with bar.delegate here* //
bar = nil; // is memory for bar.delegate free'd here,

// bar is free'd here, and would have been whether or not you set it to nil
// moreover - bar's delegate is set to nil because it was declared weak.

这是关于该主题的不错的 Apple 文档。

于 2013-06-06T14:52:34.643 回答
1
- (void)viewDidLoad
{
    [super viewDidLoad];
    BarViewController *bar = [[BarViewController alloc] init];
    // does this assignment create a "strong" reference i.e. increase retain count by 1? 

不,您将委托设置为弱,因此在分配 bar.delegate 时编译器不会强烈指向任何对象(在本例中为 SELF)。

bar 是一个局部变量,因此只要函数不返回(分配时计数增加 1,函数结束时将其删除),或者只要您不将其设置为 NIL,它就会自动保留 BarViewController 对象。

如果您没有将委托 var 指定为弱,那么是的,您会将保留计数增加到 SELF 1,并且您可能会以保留周期结束。这就是代表应该总是弱的方式。

bar.delegate = self; 
//do some useful stuff with bar.delegate here
bar = nil; // is memory for bar.delegate free'd here,
// or only after this instance of FooViewController is destroyed?
}

在这种情况下,将 bar 设置为 nil 将释放与变量 bar 相关的内存空间,它是唯一指向 BarViewController 对象的空间,所以是的,在此之后 BarViewController 也将被释放,但请记住你没有这样做是因为 ARC 会在函数结束时自动将本地 var 设置为 nil。

所有这些都在 ARC 之下。同样,在代码中使用弱委托指针是一个很好的约定,以避免可能的保留周期。

于 2013-06-06T14:24:43.590 回答