开发者

Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical)

-(void)m开发者_C百科oveOneImageNewer{
    int num = [numberOfImage intValue];
    num--;

    numberOfImage = [[NSString stringWithFormat:@"%i",num] retain];

    //Load the image
    [self loadImage];
}

-(void)moveOneImageOlder{
    int num = [numberOfImage intValue];
    num++;
    numberOfImage = [NSString stringWithFormat:@"%i",num];

    //Load the image
    [self loadImage];
}

If I hit either of them twice (or once each, basically if they get called a total of two times) I get an EXC_BAD_ACCESS. If I throw a retain on: numberOfImage = [[NSString stringWithFormat:@"%i",num]retain] it's fine though. Can someone explain why this is? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. Thanks in advance!


+stringWithFormat: doesn't contain 'new', 'alloc', 'copy', or 'retain', so it should be expected that you have to retain the return value of it if you want the new NSString it creates to stick around.

Edited to include this handy link duskwuff kindly dug up: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH


If numberOfImage is a properly declared property, e.g.

@property (copy) NSString *numberOfImage;

and it was properly synthesized (in the @implementation section for the class):

@synthesize numberOfImage;

then you can do:

- (void) moveOneImageNewer
{
    self.numberOfImage = [NSString stringWithFormat: @"%i", [self.numberOfImage intValue] - 1];

    // Load the image
    [self loadImage];
}

The property setter will take care of retaining the string and, if necessary, releasing the previous string.

FWIW, why on earth is numberOfImage a string? Why not a simple int?


numberOfImage is an instance variable or property of your class, right?

You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain).

If you do not retain it, it will get auto-released before the method is called again (and then the first line will fail, as it tries to access the previously set, now auto-released value).

Consider using properties, they have auto-generated memory management code (including releasing the old NSString when you set the new one).


You haven't retained the string object in "moveOneImageOlder", so that object gets autoreleased at the end of the event cycle and points to nothing. That's why you get the EXC_BAD_ACCESS next time you try to use it.

Use a retain to claim ownership of the NSString. Remember to release when you're done though (you can use properties to help you with this)

-(void)moveOneImageNewer{
    int num = [numberOfImage intValue];
    num--;

[numberOfImage release];
    numberOfImage = [[NSString stringWithFormat:@"%i",num] retain];

    //Load the image
    [self loadImage];
}

-(void)moveOneImageOlder{
    int num = [numberOfImage intValue];
    num++;
[numberOfImage release];
    numberOfImage = [[NSString stringWithFormat:@"%i",num] retain];

    //Load the image
    [self loadImage];
}

Add this in dealloc:

- (void)dealloc {
    [numberOfImage release];
    [super dealloc];
}


Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right.

So the second call to your method would have numberOfImage pointing to nothing, as the autorelease NSString object it used to be pointing to has already been released and deallocated since you didn't retain it.

The part that is directly causing the crash is [numberOfImage intValue] when you call the method a second time, as you sending a message to an object (pointed to by numberOfImage) that no longer exist.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜