这是来自previous one的后续问题,其中可能包含太多间接细节。请考虑以下代码:
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
报告通过其代表选择的内容。
在上面的代码中,当我在bar
中将nil
设置为FooViewController.m
时,为bar.delegate
预留的内存会发生什么变化?一方面,我认为将bar
设置为nil
可能会导致bar.delegate
也被设置为nil
,作为被释放的bar
对象的一部分。另一方面,我对weak
引用的理解是,只有在没有任何人强烈指向它时才释放内存。因此,如果bar.delegate = self
创建了对delegate
的强引用(是吗?),bar.delegate
是否有可能仍以某种方式保存指向FooViewController
实例的指针,即使{ {1}}现在是bar
?这里是否存在内存泄漏的可能性?
修改
所以我正在考虑的方式是,nil
强烈指向我们的UIWindow
实例作为根视图控制器,而我们的BarViewController实例将弱点指向我们的{{1}实例作为其代表。因此,即使我们设置FooViewController
,FooViewController
弱指向仍然至少有一个来自bar = nil
的强指针的对象,因此bar.delegate
无法自由基于“当没有其他人强烈指出它时,弱势财产被释放”的前提是什么?
答案 0 :(得分: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.
答案 1 :(得分: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是一个局部变量,因此只要函数没有返回它就会自动保留BarViewController对象(当指定函数时将计数增加1并在函数结束时将其删除),或者只要你没有将它设置为NIL。
如果你没有指定委托变量为弱,那么是的,你将保留计数增加到SELF,你可能最终会有保留周期。这就是代表应该总是很弱的方式。
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会在函数结束时自动将局部变量设置为nil。
所有这些都在ARC下。同样,如果您在代码中执行代理指针较弱,这是一个很好的约定,以避免可能的保留周期。