IOS分配的对象稍后在此执行路径中不会引用保留计数+1

时间:2012-11-08 17:49:27

标签: ios sdk memory-leaks instance-variables self

在我的appDelegate.h文件中,我这样做:

CLLocationManager       *locationManager;

@property (nonatomic, retain) CLLocationManager *locationManager;

然后在.m文件中:

...

@synthesize locationManager;
...
if ([CLLocationManager locationServicesEnabled])
{

    [myGizmoClass setLocationManagerDisabled:FALSE];

    self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;

    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];


    [self.locationManager startUpdatingLocation];

...

然而,我在XCode 4.5中获得以下内容(见附图)

Object leaked: allocated object is not referenced later in this code execution path

(对象泄露:此代码执行路径后面未引用已分配的对象)

到底是什么?我在那条线之后立即引用它。

我没有看到这个问题。 PS:没有崩溃,或任何事情。让我说清楚。 按原样工作。我只是讨厌这个错误。我很确定我错过了一些愚蠢的东西。有人可以帮忙吗?

请不要发布任何关于“你不必再做@property”的内容等等。这段代码是为xcode 3.5-4~ish写的,我更喜欢具体因为我讨厌有在XCode 4.5允许的简写和旧项目需要的简写之间来回翻转(并且仍然在他们的源代码中)。所以我仍然使用.h文件中的完整定义。我认为编程风格的主要变化将伴随着应用程序的下一次重大更新。 (感谢您的理解)

4 个答案:

答案 0 :(得分:12)

问题

如果这是非ARC(我认为是这样),那么请考虑一下这是如何工作的:

self.locationManager = [[CLLocationManager alloc] init];
    ^                                        ^
    Retains on setting                       |
                                             Retains when allocating

为什么我在设置属性时会保留?

@property (nonatomic, retain) CLLocationManager *locationManager;
                         ^
                    This is why

合成属性时,您将生成一个getter和setter(在大多数情况下)。 nonatomicretain关键字为合成提供了提示; nonatomic包装设置并进入@synchronized(self)以确保一次只有一个线程正在对其进行操作,retain告诉设置者保留您放入的任何值它。 重要的是要注意(对于旧版本的Xcode,而不是4.5),如果你不合成,那么这些将不会生效


在你的情况下,你保留了两次。因此,如果在任何地方都没有释放,那么内存将被泄露。它很容易修复,只需使用:

self.locationManager = [[[CLLocationManager alloc] init] autorelease];

为什么会这样?

如果没有,那么从方法返回的自动释放对象将无法正确保留!

替代解决方案

如果您不喜欢添加自动释放,请简单地分配给基础实例变量。

locationManager = [[CLLocationManager alloc] init];

在所有情况下......

确保在最合适的时间发布您拥有的内容,这些内容不会自动发布。对于保留的属性,self.locationManager = nil就足够了。对于替代解决方案,您需要执行[locationManager release];

答案 1 :(得分:2)

@property定义为retain。因此,以下行:

self.locationManager = ...

在语义上等同于:

[self setLocationManager:...]

保留右侧的任何内容。但是你在右边提供的是一个拥有的参考。所以:

[[CLLocationManager alloc] init] // gives an owning reference

self.locationManager = ...       // retains your owning reference; you've now
                                 // incremented the reference count twice

您的位置经理将被泄露。

答案 2 :(得分:1)

检查此代码:

CLLocationManager *location = [[CLLocationManager alloc] init];

self.locationManager = location;

[location release];

或者您需要这样做:

self.locationManager = [[[CLLocationManager alloc] init] autorelease];

[[CLLocationManager alloc] init]使retainCount为1。

self.locationManager使retainCount增加1。

答案 3 :(得分:1)

在@property中,我看到你已经表明你希望locationManager保留。因此,为self.locationManager分配内容会使保留计数增加到1。但是,既然你也调用了alloc,那么现在将保留计数颠倒到两个(这将导致泄漏)。

解决方案:从alloc语句中删除self:

  

locationManager = [[CLLocationManager alloc] init];