【问题标题】:Memory Management Confusion Objective C内存管理混淆目标 C
【发布时间】:2013-04-16 07:16:56
【问题描述】:

问题 1

Place *place = [[[Place alloc] initwithCoordinate:location anotationType:CSMapAnnotationTypeStart] autorealease];
place.name = name;
place.description = description;
place.strUniqueIdentity = uniqueIdentity;
NSLog(@"Unique identity %@",uniqueIdentity);

PlaceMark *marker = [[PlaceMark alloc] initWithPlace:place annotationType:MapAnnotationTypePin];
return [marker autorelease];

当我分析 xcode 4.6.2 中的代码时,它在倒数第二行显示“对象已发送 -autorelease 太多次”。 我不明白为什么会这样显示。

问题 2:

return [[[OAProblem alloc] initWithResponseBody:response] autorelease];

在这一行中,它显示“存储在'self'中的对象的潜在泄漏”。

【问题讨论】:

  • 你为什么不用ARC
  • 看起来是对的,您是否对类本身的内存管理进行了一些修改,例如 initWithCoordinate 或 initWithPlace。确定您显示的范围内没有其他内容吗?
  • @msgambel:我总是使用手动引用计数,因为它比某些人指定的 ARC 更好。
  • 你的代码sn-p和抓屏不一样
  • @Yash:除非您手头有具体问题,否则绝对没有理由不使用 ARC(您始终可以在 ARC 项目中将特定有问题的文件标记为 MRC)。 ARC 编译为 MRC。 Clang 将高度复杂的算法应用于您的代码库,以便找出最佳插入 retain/release 的位置,省略所有不必要的(因此导致更快的代码)。现在你的决定似乎是基于纯粹的猜测和传闻。 ARC 随时为您提供帮助。用它。 (此外,ARC 强制执行严格的方法命名约定,这也是一件好事。)

标签: iphone ios objective-c ipad xcode4


【解决方案1】:

我的问题第一部分的答案是初始化方法中的小'w'

-initwithCoordinate: anotationType:

根据 Cocoa 命名约定,我必须使用大写字母“W”。

我将初始化方法替换为

-initWithCoordinate: anotationType:

我的问题第二部分的答案是在两个失败路径中添加一个 [self release]

Xcode 对 OAProblem.c 的分析器警告非常无用。

真正有问题的代码在 init 方法中。警告(在这种情况下)意味着“一个 init 方法返回 nil 而不释放由 alloc 分配的对象”。修复方法是在两个失败路径中添加 [self release]:

- (id)initWithProblem:(NSString *) aProblem
{
    NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem];
    if (idx == NSNotFound) {
        [self release]; // <-- Add this line to fix the warning
        return nil;
    }

    return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]];
}

initWithResponseBody 也是如此。

【讨论】:

  • 顺便说一句,“注释”用两个“n”拼写。 ;)
  • 是的,这是一个打字错误。但我认为这对命名约定无关紧要。
【解决方案2】:

Xcode 对 OAProblem.c 的分析器警告非常无用。

真正有问题的代码在 init 方法中。警告(在这种情况下)意味着“一个 init 方法返回 nil 而不释放由 alloc 分配的对象”。解决方法是在两个失败路径中添加[self release]

- (id)initWithProblem:(NSString *) aProblem
{
    NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem];
    if (idx == NSNotFound) {
        [self release]; // <-- Add this line to fix the warning
        return nil;
    }

    return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]];
}

initWithResponseBody 也是如此。

【讨论】:

    【解决方案3】:

    Why are you not using Arc? 的回答完全无效。 OP 特别询问为什么会在他自己的环境中发生这种情况。所以:

    你能告诉我们你的:

    Place *place = [[Place alloc] initwithCoordinate:location anotationType:CSMapAnnotationTypeStart];
    

    还可以使用工具,看看您的项目是否确实存在问题。并非静态分析器显示的所有内容实际上都是问题。可能会出现一些误报。

    所以从您的回复中可以看出:

     -(id)initwithCoordinate:(CLLocationCoordinate2D)coordinate anotationType:(CSMapAnnotationType)anotationType{ 
    self.latitude = coordinate.latitude; 
    self.longitude = coordinate.longitude; 
    self.mapAnnotationType = anotationType; 
    return self;
     }
    

    应该是这样的:

    -(id)initwithCoordinate:(CLLocationCoordinate2D)coordinate anotationType:(CSMapAnnotationType)anotationType{
        if (self = [super init])
        {
            self.latitude = coordinate.latitude;
            self.longitude = coordinate.longitude;
            self.mapAnnotationType = anotationType;
        }
            return self;
    }
    

    这就是他抱怨保留计数 == 0 的对象的原因。

    【讨论】:

    • 首先感谢您的回复。初始化为 -(id)initwithCoordinate:(CLLocationCoordinate2D)coordinate annotationType:(CSMapAnnotationType)anotationType{ self.latitude = coordinate.latitude; self.longitude = 坐标.经度; self.mapAnnotationType = annotationType;回归自我; } 我认为与内存管理无关。
    • @JackyBoy: init 不保留对象,alloc 保留。 [Foo alloc] 返回一个保留计数为 1 的实例(理论上,至少是这样),因此 [[Foo alloc] init] 也是如此。即使init 被错误地定义为- (id)init {return self;}
    • 这不是问题,问题是方法名称中的小写'w'。
    【解决方案4】:

    您收到警告,因为initwithCoordinate 的拼写错误。根据 Cocoa 命名约定,它应该是 initWithCoordinate(大写 W)。

    【讨论】:

    • @Yash 第二个问题的代码看起来没问题。如果你把它分成两个语句,你还会收到警告吗?
    • 每行都会收到一个警告?
    【解决方案5】:
    Place *place = [[Place alloc] initwithCoordinate:location anotationType:CSMapAnnotationTypeStart];
    place.name = name;
    place.description = description;
    place.strUniqueIdentity = uniqueIdentity;
    NSLog(@"Unique identity %@",uniqueIdentity);
    
    PlaceMark *marker = [[PlaceMark alloc] initWithPlace:place    annotationType:MapAnnotationTypePin];
    [place release];//I think you are release place object, cause of memory leak
    return [marker autorelease];
    

    【讨论】:

    • autorelease 在 autorealease 池中释放对象,而不是在它被调用的地方我也已经尝试过了。
    【解决方案6】:

    更好的解决方案是将您的应用转换为 ARC(自动引用计数)。它可能会占用内存问题。

    将您的 xcode 项目编辑>重构>转换为目标 C ARC> 确定

    【讨论】:

    • 当有人发布内存管理问题时,为什么每个人都会跳起来喊 ARC?朋友,有很多应用程序没有使用 ARC,并且有许多开发人员更喜欢使用手动内存管理。如果你不知道,手动内存管理仍然是允许的。
    • 对于新代码 ARC 更好,但这个答案应该是对问题的评论。
    • @JeremyP:您所说的新代码是什么意思以及它如何变得更好。请解释一下。
    • @Yash:如果您从头开始编写项目而不使用使用手动引用计数的现有代码,ARC 会更好,因为它会自动处理所有这些内容。
    • 什么东西?就是因为这样说,人们不明白你应该如何处理记忆。这不是 GC...如果您不小心,您可能会遇到一些讨厌的事情。
    猜你喜欢
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 2012-12-13
    • 1970-01-01
    相关资源
    最近更新 更多