简体   繁体   English

为什么这会导致崩溃?

[英]Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical) 我将这两个按钮连接到这两种方法(它们几乎相同)

-(void)moveOneImageNewer{
    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. 如果我打了两次(或者一次,基本上是两次),我会得到一个EXC_BAD_ACCESS。 If I throw a retain on: numberOfImage = [[NSString stringWithFormat:@"%i",num]retain] it's fine though. 如果我保留: numberOfImage = [[NSString stringWithFormat:@"%i",num]retain]问题。 Can someone explain why this is? 有人可以解释为什么吗? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. 我在乐器上做了一个NSZombie,并将其追溯到此stringWithFormat调用。 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. + stringWithFormat:不包含'new','alloc','copy'或'retain',因此,如果希望它创建的新NSString能够保留,则应该保留它的返回值。

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 经过编辑,包括了这个方便的链接,请仔细挖掘: 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, eg 如果numberOfImage是正确声明的属性,例如

@property (copy) NSString *numberOfImage;

and it was properly synthesized (in the @implementation section for the class): 并正确地进行了合成(在该类的@implementation部分中):

@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 ? FWIW,为什么地球上的numberOfImage是字符串 Why not a simple int? 为什么不使用简单的int?

numberOfImage is an instance variable or property of your class, right? numberOfImage是您的类的实例变量或属性,对吗?

You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain). 您将其设置为stringWithFormat (返回自动释放的NSString),而无需声明该对象的所有权(通过调用stringWithFormat )。

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). 考虑使用属性,它们具有自动生成的内存管理代码(包括在设置新NSString时释放旧的NSString)。

Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right. 好吧,如果我是对的,NSString类方法“ stringWithFormat”将返回一个自动释放的NSString对象。

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. 因此,对方法的第二次调用将使numberOfImage指向空,因为它曾经指向的自动释放NSString对象已经被释放并释放,因为您没有保留它。

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. 当您第二次调用该方法时,当您向不再存在的对象(由numberOfImage指向)发送消息时,直接导致崩溃的部分是[numberOfImage intValue]

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. 您尚未在“ moveOneImageOlder”中保留字符串对象,因此该对象在事件周期结束时自动释放,并且没有指向任何对象。 That's why you get the EXC_BAD_ACCESS next time you try to use it. 这就是为什么您下次尝试使用EXC_BAD_ACCESS的原因。

Use a retain to claim ownership of the NSString. 使用保留声明对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: 在dealloc中添加:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM