简体   繁体   中英

NSMutableArray EXC_BAD_ACCESS on contained objects

I have a class where I implement a NSMutableArray of objects. Now, when the phone goes into landscape mode, all of the objects in the NSMutableArray are deleted from the view (but not from the NSMutableArray), then when the phone goes back to portrait mode, I put all the objects contained in the NSMutableArray into the view, but when I try to access the first object I receive: EXC_BAD_ACCESS.

This is my code:

- (void) setObjects:(BOOL)hidden andWindow:(UIWindow *)win andTxt:(UITextView *)txt andTarget:(id) target {
    //view
    key = [win.subviews objectAtIndex:0];
    key.hidden = hidden;
    buttons = [[NSMutableArray alloc] initWithCapacity:1]; //my array
    txtsms = txt;
        [...]
}

- (void) addButton:(button *)but {
    [key addSubview:[but returnButton]];
    [buttons addObject:but];
    [but release];
}

- (void) hiddenAllKey {
    for (UIView *subview in [key subviews])
        if ((subview.tag <= startSpecialPunctuation+1)&&(subview.tag >= spaceButton+1)) 
            [subview removeFromSuperview];
}

- (void) showAllKey {   
    for(int i = 0; i < [buttons count]; ++i)
             [key addSubview:[[buttons objectAtIndex:i] returnButton]]; //this is the problem :|
}

As Joe Blow said, this is wrong:

- (void) addButton:(button *)but {
    [key addSubview:[but returnButton]];
    [buttons addObject:but];
    [but release];
}

but should not be released in that method. Similarly, this strikes fear in my heart:

- (void) setObjects:(BOOL)hidden andWindow:(UIWindow *)win andTxt:(UITextView *)txt andTarget:(id) target {
    //view
    key = [win.subviews objectAtIndex:0];
    key.hidden = hidden;
    buttons = [[NSMutableArray alloc] initWithCapacity:1]; //my array

Where do you release buttons ? Does your app only ever call that method once? If not, then you'll be leaking buttons .

Try build and analyze on your code, fixing any problems that it identifies. If it still crashes, post the backtrace of the crash

- (void) hiddenAllKey {
    for (UIView *subview in [key subviews])
        if ((subview.tag <= startSpecialPunctuation+1)&&(subview.tag >= spaceButton+1)) 
            [subview removeFromSuperview];
}

This is subtly wrong too. You are removing elements from a list you are enumerating using fast enumeration. It can (should) fail easily.

Previously, I've written a category on UIView to do a remove all, that was doable with a simple while loop. Now, what you're trying to do... you might do a for loop where you manage the iterated index yourself, ie when you don't remove, you increment, else you keep it the same.

EDIT: suggestion of solution:

for (int idx = 0; idx < [[key subviews] count]; )
{
    UIView *subview = [[key subviews] objectAtIndex: idx];
    if ((subview.tag <= startSpecialPunctuation + 1) && (subview.tag >= spaceButton + 1))
    {
        [subview removeFromSuperview];
    }
    else
    {
        idx++;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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