7

在我的 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 中得到了以下内容(见附图)

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

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

有没有搞错?我在该行之后立即引用它。

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

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

4

4 回答 4

12

问题

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

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

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

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

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


就您而言,您保留了两次。因此,如果任何地方都没有释放,那么内存就会泄漏。修复很简单,只需使用:

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

为什么会这样?

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

替代解决方案

如果您不喜欢添加自动释放,只需分配给底层实例变量即可。

locationManager = [[CLLocationManager alloc] init];

在所有情况下...

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

于 2012-11-08T17:54:32.550 回答
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

您的位置管理器将被泄露。

于 2012-11-08T17:54:10.540 回答
1

检查此代码:

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

self.locationManager = location;

[location release];

或者你需要这样做:

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

[[CLLocationManager alloc] init]使到retainCount1。

self.locationManager使retainCountto 增加 1。

于 2012-11-08T17:54:45.643 回答
1

在@property 中,我看到您已表明您希望 locationManager 保留。因此,为 self.locationManager 分配一些东西会将保留计数增加到 1。但是,由于您还调用了 alloc,因此现在将保留计数增加到 2(这将导致泄漏)。

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

locationManager = [[CLLocationManager alloc] init];

于 2012-11-08T17:57:24.487 回答