当分配给保留属性时,我应该保留自动释放的对象吗?
在我保留的属性之一的 getter 中,我将 NSArray 分配并分配给我的模型对象(“models”)。然后我使用“sortedArrayUsingSelector:”方法对该 NSArray 进行排序。根据文档,这会返回一个自动释放的 NSArray。然后我将其重新分配给我的“模型”数组。
起初,我从未保留过这个自动释放的排序数组,并且发现当我从堆栈中弹出这个 viewController 时,我的应用程序会崩溃,说我正在尝试减少已释放对象或类似对象的引用计数。然后我添加了一个保留,如下面的代码所示,一切正常。
我的问题是,即使我在其声明中保留此属性并在我的 dealloc 中释放它,我应该保留自动释放的对象是否正确?
- (NSArray *)models {
if (!models) {
models = [[NSArray alloc] initWithArray:[self.modelDictionary allKeys]];
models = [[models sortedArrayUsingSelector:@selector(compare:)] retain];
}
return models;
}
In the getter for one of my retained properties, I allocate and assign an NSArray to my model object("models"). I then sort that NSArray using "sortedArrayUsingSelector:" method. According to the docs, this returns an autoreleased NSArray back. I then reassign that to my "models" array.
At first, I never retained this autoreleased sorted array and found that when I popped this viewController off the stack, my app would crash, saying that I was trying to decrement the reference count on a deallocated object or something of the sort. I then added a retain as you can see in the code below, and all is ok.
My question is, is this correct that I should have to retain the autoreleased object, even though I am retaining this property in its declaration and releasing it in my dealloc?
- (NSArray *)models {
if (!models) {
models = [[NSArray alloc] initWithArray:[self.modelDictionary allKeys]];
models = [[models sortedArrayUsingSelector:@selector(compare:)] retain];
}
return models;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一般来说,如果您希望自动释放的对象保留下来,则必须
保留
它。此代码存在几个问题:
您正在泄漏第二个
models=
行代码中alloc/init
d 的数组您说“在其声明中保留此属性,但在上面您直接分配给实例变量的代码,绕过可能由
@synthesize
生成的 setter 方法,
它是一个getter方法,可以改变所获取的变量的状态...而这种延迟初始化可能很有吸引力,但必须非常小心地完成。核心数据竭尽全力——通过相当多的内部复杂性——以允许以这种方式进行惰性状态填充。上面的代码还意味着
models
属性的键值观察器在 getter 执行时不会看到变化。然而,如果您从 getter 手动调用willChangeValueForKey:/didChangeValueForKey:
,您最终会从getter
内部发送更改通知,很可能会导致某些内容消耗value before 调用 getter 的人首先检索该值。听起来很混乱?这可能会或可能不会引起问题。根据我的经验,它很可能有一天会导致问题。它
一些建议:
如果可以的话,使用核心数据。为了使 Core Data 非常高效并与系统很好地集成,我们投入了大量的工程工作。
将 getter/setter 与其余逻辑分开。更有可能的是,您的应用程序中存在一个逻辑点,您需要“获取”模型。当你这样做时,告诉对象通过其他一些方法来出错,然后获取模型。这可能看起来很痛苦,但与查询该图以获取信息相比,对象图的构建在很大程度上是一项专门的任务(或使用 Core Data,它有一个解决方案)。
In general, if you want an autoreleased object to stick around, you must
retain
it.There are a couple of issues with this code:
you are leaking the array that is
alloc/init
d with the secondmodels=
line of codeyou said "retaining this property in its declaration, but in the above code you are assigning to the instance variable directly, bypassing the setter method that may have been generated by
@synthesize
it is a getter method that changes the state of the variable being got... while this kind of lazy initialization can be attractive, it must be done with extreme care. Core Data goes to great lengths -- through quite a bit of internal complexity -- to allow for lazy population of state in this fashion. The above code would also mean that Key-Value Observers of the
models
property would not see the change when the getter is executed. Yet, if you callwillChangeValueForKey:/didChangeValueForKey:
manually from the getter, you'll end up sending a change notification from within thegetter
, quite likely causing something to consume the value before whoever called the getter first retrieves the value. Sound confusing? It is -- that may or may not cause a problem. It is, in my experience, likely to cause a problem some day.Some suggestions:
use Core Data, if you can. A truly huge amount of engineering work has been invested in making Core Data very efficient and very well integrated with the system.
separate getter/setters from the rest of your logic. More likely than not, there is a logical point in your app where you'll need to "get" the models. When you do, tell the object to fault 'em in through some other method then get the models. It may seem like a pain, but construction of the object graph is very much a specialized task vs. querying that graph for information (or use Core Data, which has a solution for this).
除非我遗漏了一些东西,否则看起来您只是将结果设置为实例变量之一。我认为您应该使用您的属性。
如果没有
self.
部分,您就不会使用setter 方法,因此从不保留任何内容。Unless I"m missing something, it looks like you are just setting the result to one of your instance variables. I think you should be using your property instead.
Without the
self.
part, you are not using the setter method, and thus never retaining anything.谢谢你!我明白你的意思。我想我很困惑,并认为在 getter 中调用 self.models 会创建无限循环。我现在明白了,这只是我从 getter 内部调用 getter,而不是从 getter 内部调用 setter。我将代码更改为:
一切都编译并正常工作...这看起来是一个更正确的解决方案吗?感谢您抽出时间。
Thank you! I understand what you mean. I think I got confused and thought that calling self.models in my getter would create an infinite loop. I see now that it is just if I call the getter from within the getter not the setter from within the getter. I changed my code to this:
everything compiles and works fine...does this look like a more correct solution? Thanks for your time.