方法结束时的EXC_BAD_ACCESS

时间:2011-10-21 13:52:14

标签: iphone objective-c ios exc-bad-access

在这个方法中,我在sqlite数据库中添加了UITextFields,图像和其他字符串的内容。一切正常。我的意思是,当我按下“添加”按钮时,会出现“确定”图像,声音播放和所有内容都会添加到数据库中(我可以检查重启应用程序)。但在所有这些之后,我在“main.m”中出现了这个错误

这是方法:

-(IBAction)addItem:(id)sender { //gestione pulsante aggiunta elemento
    if (([itemNameField.text length] == 0) || ([priceField.text length] == 0) || ([priceField.text doubleValue] == 0.0) || ((incomeOutcome.selectedSegmentIndex != 0) && (incomeOutcome.selectedSegmentIndex != 1))) {
        if ([itemNameField.text length] == 0) {
        statusLabel.text = [[NSString alloc] initWithFormat: @"Specificare un nome."];
        } else if (([priceField.text length] == 0) || ([priceField.text doubleValue] == 0.0)) {
            statusLabel.text = [[NSString alloc] initWithFormat: @"Specificare un prezzo."];
        } else if ((incomeOutcome.selectedSegmentIndex != 0) && (incomeOutcome.selectedSegmentIndex != 1)) {
            statusLabel.text = [[NSString alloc] initWithFormat: @"Specificare \"Income/Outcome\" ."];            
        }
        if (!categoriaLabel.hidden) {
            [self hideThemAll];
        }
        [incomeOutcome setSelectedSegmentIndex:-1];
        statusLabel.hidden = NO;
        error = true;
        [self playSound];
        [ok setImage:[UIImage imageNamed:@"error.png"]];
        ok.hidden = NO;
        return;
    }
    //apriamo il database
    sqlite3 *db;
    int dbrc; //Codice di ritorno del database (database return code)
    iWalletAppDelegate *appDelegate = (iWalletAppDelegate*) [UIApplication sharedApplication].delegate;
    const char *dbFilePathUTF8 = [appDelegate.dbFilePath UTF8String];
    dbrc = sqlite3_open(dbFilePathUTF8, &db);
    if (dbrc) {
        NSLog(@"Impossibile aprire il Database!");
        return;
    }
    //database aperto! Inseriamo valori nel database.
    sqlite3_stmt *dbps; //Istruzione di preparazione del database
    NSString *insertStatementsNS;
    if (incomeOutcome.selectedSegmentIndex == 0) {
        insertStatementsNS = [NSString stringWithFormat: @"insert into \"shoppinglist\" (item, price, groupid, incout, path,  dateadded) values (\"%@\", \"%@\", \"Entrata\", %d, \"%@\", DATETIME('NOW'))", itemNameField.text, priceField.text, incomeOutcome.selectedSegmentIndex, imagePath];
    } else if ([categoryNameField.text length] != 0) { 
        insertStatementsNS = [NSString stringWithFormat: @"insert into \"shoppinglist\" (item, price, groupid, incout, path, dateadded) values (\"%@\", \"%@\", \"%@\", %d, \"%@\", DATETIME('NOW'))", itemNameField.text, priceField.text, categoryNameField.text, incomeOutcome.selectedSegmentIndex, imagePath]; 
    } else { 
        insertStatementsNS = [NSString stringWithFormat: @"insert into \"shoppinglist\" (item, price, groupid, incout, path, dateadded) values (\"%@\", \"%@\", \"Varie\", %d, \"%@\", DATETIME('NOW'))", itemNameField.text, priceField.text, incomeOutcome.selectedSegmentIndex, imagePath];
    }
    const char *insertStatement = [insertStatementsNS UTF8String];
    dbrc = sqlite3_prepare_v2(db, insertStatement, -1, &dbps, NULL);
    dbrc = sqlite3_step(dbps);

    //faccio pulizia rilasciando i database
    sqlite3_finalize(dbps);
    sqlite3_close(db);

    // Pulisci i campi e indica successo nello status
    statusLabel.hidden = NO;
    statusLabel.text = [[NSString alloc] initWithFormat: @"Aggiunto %@", itemNameField.text];

    itemNameField.text = @"";
    priceField.text = @"";
    categoryNameField.text = @"";
    imagePath = @"";
    [incomeOutcome setSelectedSegmentIndex:-1];
    error = false;
    [self hideThemAll];
    [self playSound];
    [ok setImage:[UIImage imageNamed:@"ok.png"]];
    ok.hidden = NO;
    nome = @"";
    prezzo =@"";
    [photoPreview setImage:[UIImage imageNamed:@"noPhoto.png"]];
    [[self parentViewController]dismissModalViewControllerAnimated:YES];
}    

修改

感谢Isaac I(也许)发现了这个问题:我没有保留我从相机拍摄的照片。

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [picker dismissModalViewControllerAnimated:YES];
    int r = arc4random() % 9999;
    NSDate *date = [NSDate date];
    NSString *photoName = [dateNameFormatter stringFromDate:date];
    photoName = [photoName stringByAppendingString:[NSString stringWithFormat:@"%d", r]];

    if (imagePath) {
        [imagePath release];
    }
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    imagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", photoName]];
    [imagePath retain];

    UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];

    // ----- CODE FOR SCALE THE IMAGE ----- //
    if (picture.size.width == 1936) {
        picture = [picture scaleToSize:CGSizeMake(480.0f, 720.0f)];
    } else {
        picture = [picture scaleToSize:CGSizeMake(720.0f, 480.0f)];
    }

    photoPreview.image =  picture;

    photoPreview.contentMode = UIViewContentModeScaleAspectFit;

    CGRect frame = photoPreview.frame;
    if (picture.size.width == 480) {
        frame.size.width = 111.3;
        frame.size.height =167;
    } else {
        frame.size.width = 167;
        frame.size.height =111.3;
    }
    photoPreview.frame = frame;
    // ----- ----- - END CODE - ----- ----- //    

    NSData *webData = UIImagePNGRepresentation(picture);
    CGImageRelease([picture CGImage]);
    [webData writeToFile:imagePath atomically:YES];
    [picture retain]; // <-- This little thing here!
    //imgPicker = nil;
}

现在它有效!但如果你能看到其他问题,请让我注意一下。

3 个答案:

答案 0 :(得分:4)

没有理由像这样创建NSString

 statusLabel.text = [[NSString alloc] initWithFormat: @"Specificare un nome."];

简单写一下

statusLabel.text = @"Specificare un nome.";

也许这不是EXC_BAD_ACCESS的原因,但至少可以避免几次内存泄漏。

答案 1 :(得分:3)

当您尝试访问已解除分配的内存时,通常会发生EXC_BAD_ACCESS。在您的代码示例中,我没有看到任何[对象释放]调用(这完全是另一个问题,除非您碰巧使用ARC)。但我猜这个错误是在这个方法范围之外进行的调用的结果 - 某些东西正在过早地释放。

您可以粘贴整个班级,或者考虑使用“工具”工具“Zombies”来识别可能导致此问题的悬挂指针。

答案 2 :(得分:0)

在我看来isaac是对的。我只想添加一个猜测。调用

时,最有可能发生错误
[[self parentViewController]dismissModalViewControllerAnimated:YES];

到目前为止,我认为,你在parentViewController中已经发布了一些内容,所以当你试图将它显示回来时,程序会转向已发布的变量并让你崩溃。

只需借助断点即可轻松检测到它。