有趣的内存错误 - NSMutableArray被一致地替换

时间:2012-02-14 04:59:42

标签: ios ipad nsmutablearray

在我的iPad应用程序中,我有以下功能:

+ (void)addDot:(Dot *)d {
    if(dots == nil)
        dots = [[NSMutableArray alloc] init];

    NSLog(@"before adding, dots = %@",dots);
    NSLog(@"adding dot %@",d);
    [dots addObject:d];
    NSLog(@"dots is now %@",dots);
}

请注意,打印点会导致x,y坐标以空格分隔。

每当主体点击屏幕时,都会绘制一个点,并调用此方法,这会添加一个点。请注意,dots在此函数所在的类的顶部定义为static NSMutableArray *dots。有些奇怪的事情正在发生。数组的每个元素都被替换。点击屏幕后,在开始时查看NSLog的此输出,制作2个点:

before adding, dots = (
)
2012-02-13 23:58:48.159 MoreMost[520:707] adding dot 418.000000 548.000000
2012-02-13 23:58:48.161 MoreMost[520:707] dots is now (
    "418.000000 548.000000"
)
2012-02-13 23:58:48.748 MoreMost[520:707] before adding, dots = (
    "635.000000 410.000000"
)
2012-02-13 23:58:48.749 MoreMost[520:707] adding dot 635.000000 410.000000
2012-02-13 23:58:48.750 MoreMost[520:707] dots is now (
    "635.000000 410.000000",
    "635.000000 410.000000"
)

查看整个数组如何被传入元素替换?为什么是这样?不,该函数不会在代码中的任何其他位置调用。每次用户点击屏幕在该位置画一个点时,它只被调用一次。)

请注意,程序中的其他任何位置都没有使用这些点。只有这个功能

这是Dot的实现:

#import "Dot.h"

@implementation Dot
@synthesize tapPosition;
CGRect frame;
UIColor *dotColor;

float radius = 20;

- (id)initWithTapPosition:(CGPoint)pt color:(UIColor *)col {
    if(self = [super init]) {
    tapPosition = pt;
    float topLeftX = pt.x - radius;
    float topLeftY = pt.y - radius;
    if(topLeftX + (radius*2) >= 1024)
        return nil;
    if(topLeftY + (radius*2) >= 728)
        return nil;
    if(topLeftY <= 0 || topLeftX <= 0)
        return nil;

    frame = CGRectMake(topLeftX, topLeftY, radius*2, radius*2);
    dotColor = col;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
   Dot *dot = [[[self class] allocWithZone:zone] initWithTapPosition:tapPosition color:dotColor];
   return dot;
}

- (CGRect)getFrame {
    return frame;
}

- (UIColor *)getColor {
    return dotColor;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%f %f",frame.origin.x,frame.origin.y];
}

@end

和标题:

    #import <Foundation/Foundation.h>

@interface Dot : NSObject {
@public
    CGPoint tapPosition;
}

@property (nonatomic, assign) CGPoint tapPosition;

- (CGRect)getFrame;
- (id)initWithTapPosition:(CGPoint)pt color:(UIColor *)col;

- (UIColor *)getColor;
@end

2 个答案:

答案 0 :(得分:1)

移动

CGRect frame;
UIColor *dotColor;
CGPoint tapPosition;
float radius = 20;

@implementation@interface

@interface Dot : NSObject
{
   CGRect frame;
   // etc.
}
...
@end

您声明它们的方式使它们实际上是“全局变量”,因此所有Dot实例将共享相同的值。将它们放在@interface中使它们成为“实例变量”,这样每个Dot都可以有不同的值。


旧答案

请注意

[dots addObject:d];

仅添加点d引用。如果您稍后就地修改点,例如

d.x = 123;
d.y = 456;

然后数组中的那个也会看到相同的变化。

您需要添加副本,例如

[dots addObject:[d copy]];
// note: you need to implement -copyWithZone: with the <NSCopying> protocol

答案 1 :(得分:0)

您的点类需要修改,以便tapPosition不是静态变量。

·H

@interface Dot : NSObject{
    @public
    CGPoint tapPosition;
}
@property (nonatomic, assign) CGPoint tapPosition;
@end

的.m

@implementation Dot
@synthesize tapPosition;
//...
@end