I'm writing a project where a very straightforward assignment is sporadically failing. Fascinated with this result and curious to see what y'all make of it.
我正在编写一个项目,其中一项非常简单的任务偶尔会失败。着迷于这个结果,并好奇地看到你们所做的一切。
I've got a project with a large data set, and I'm creating and display a modal window to present some details about a new class instance. So I've got a window with a custom window controller class, with the following code:
我有一个包含大型数据集的项目,我正在创建并显示一个模态窗口,以显示有关新类实例的一些细节。所以我有一个带有自定义窗口控制器类的窗口,其代码如下:
MyWindowController.h:
#import <DataModel.h>
@interface MyWindowController : NSWindowController
@property (nonatomic, weak) FooClass *fooInstance;
@end
MyWindowController.m:
@implementation MyWindowController
@synthesize fooInstance = _fooInstance;
-(void) init {
self = [super init];
if (self) {
self.fooInstance = [FooClass new];
}
return self;
}
@end
Totally cookie-cutter, right? But when I first added the form and ran it a bunch of times, the assignment failed over and over again. self.fooInstance kept coming back as nil. I even confirmed that the FooClass initializer was running (stepped right through it) and returning a non-null pointer to a valid FooClass instance. And yet, after the assignment line, self.fooInstance remained null.
完全千篇一律,对吧?但是当我第一次添加表单并运行它多次时,分配失败了一遍又一遍。 self.fooInstance一直没回来。我甚至确认FooClass初始化程序正在运行(直接通过它)并返回一个非空指针指向有效的FooClass实例。然而,在赋值行之后,self.fooInstance仍为null。
I ran it a bunch of times, watching this same result over and over again. Then, I replaced just the assignment statement with this:
我跑了很多次,一遍又一遍地看着同样的结果。然后,我用这个替换了赋值语句:
FooClass *foo = [FooClass new];
self.fooInstance = foo;
...and the assignment suddenly started working, and it's run consistently ever since. Even when I reverted the code back to self.fooInstance = [FooClass new], it's worked perfectly.
...而且任务突然开始起作用,从那时起它一直在运行。即使我将代码恢复为self.fooInstance = [FooClass new],它仍然完美无缺。
I couldn't believe it... until I saw it happen AGAIN, in the same project, while banging out the same type of window for a different class.
我无法相信......直到我看到它在同一个项目中再次发生,同时为同一个类别敲打同一类型的窗口。
I don't understand what's happening. The self.fooInstance accessors are totally @synthesized; there is no code running in the background that might be futzing with the class (it's a single-threaded modal window); and there's nothing bound to the class. It just... doesn't work. It's like the code for the window classes doesn't run right until it's run a few times to break it in.
我不明白发生了什么。 self.fooInstance访问器完全是@synthesized;没有在后台运行的代码可能与类有关(它是一个单线程模式窗口);这个班没有任何约束力。它只是...不起作用。这就像窗口类的代码在运行几次之后才能正常运行。
What in the world is happening? Does anyone even hazard a guess that might explain this behavior?
世界上发生了什么?有没有人甚至冒险猜测可能解释这种行为?
1 个解决方案
#1
3
I recommend taking a read through Mike Ash's explanation of weak pointers. This section is the relevant bit:
我建议读一下Mike Ash对弱指针的解释。这部分是相关的一点:
Weak References
First, what is a weak reference? Simply put, a weak reference is a reference (pointer, in Objective-C land) to an object which does not participate in keeping that object alive. For example, using memory management, this setter creates a weak reference to the new object:
首先,什么是弱参考?简单地说,弱引用是一个引用(指向,在Objective-C中)指向一个不参与保持该对象存活的对象。例如,使用内存管理,此setter创建对新对象的弱引用:
- (void)setFoo: (id)newFoo { _foo = newFoo; }
Because the setter does not use retain, the reference does not keep the new object alive. It will stay alive as long as it's retained by other references, of course. But once those go away, the object will be deallocated even if _foo still points to it.
因为setter不使用retain,所以引用不会使新对象保持活动状态。当然,只要它被其他参考文献保留,它就会保持活力。但是一旦它们消失,即使_foo仍然指向它,该对象也将被释放。
OK, that explains the first part, but why does the second part work?
好的,这解释了第一部分,但为什么第二部分有效呢?
Well, when you write an instance variable like:
好吧,当你编写一个实例变量时:
FooClass *foo = //assignment
The compiler says to itself "it's a really good idea to keep this thing around, (at least til the function goes out of scope under ARC), and it turns it into this:
编译器对自己说“保持这个东西是一个非常好的主意,(至少直到函数超出ARC的范围),并将其转化为:
__strong FooClass *foo = //assignment
That means whatever I assigned is retained, and therefore, because at least one object owns it, I can assign it to my weak instance variable.
这意味着保留了我分配的任何东西,因此,因为至少有一个对象拥有它,我可以将它分配给我的弱实例变量。
#1
3
I recommend taking a read through Mike Ash's explanation of weak pointers. This section is the relevant bit:
我建议读一下Mike Ash对弱指针的解释。这部分是相关的一点:
Weak References
First, what is a weak reference? Simply put, a weak reference is a reference (pointer, in Objective-C land) to an object which does not participate in keeping that object alive. For example, using memory management, this setter creates a weak reference to the new object:
首先,什么是弱参考?简单地说,弱引用是一个引用(指向,在Objective-C中)指向一个不参与保持该对象存活的对象。例如,使用内存管理,此setter创建对新对象的弱引用:
- (void)setFoo: (id)newFoo { _foo = newFoo; }
Because the setter does not use retain, the reference does not keep the new object alive. It will stay alive as long as it's retained by other references, of course. But once those go away, the object will be deallocated even if _foo still points to it.
因为setter不使用retain,所以引用不会使新对象保持活动状态。当然,只要它被其他参考文献保留,它就会保持活力。但是一旦它们消失,即使_foo仍然指向它,该对象也将被释放。
OK, that explains the first part, but why does the second part work?
好的,这解释了第一部分,但为什么第二部分有效呢?
Well, when you write an instance variable like:
好吧,当你编写一个实例变量时:
FooClass *foo = //assignment
The compiler says to itself "it's a really good idea to keep this thing around, (at least til the function goes out of scope under ARC), and it turns it into this:
编译器对自己说“保持这个东西是一个非常好的主意,(至少直到函数超出ARC的范围),并将其转化为:
__strong FooClass *foo = //assignment
That means whatever I assigned is retained, and therefore, because at least one object owns it, I can assign it to my weak instance variable.
这意味着保留了我分配的任何东西,因此,因为至少有一个对象拥有它,我可以将它分配给我的弱实例变量。