开发者

message sent to deallocated instance (probably UITableViewCell)

开发者 https://www.devze.com 2023-03-31 20:21 出处:网络
I know that a lot of folks have had this problem before and I\'ve read a lot of suggested solutions, none of which has worked out for me. I\'m working on a part of a larger project, involving three di

I know that a lot of folks have had this problem before and I've read a lot of suggested solutions, none of which has worked out for me. I'm working on a part of a larger project, involving three different views: the first view contains a UITableView with custom made cells called WeekdaySelectionWithPopoverCellController. This cell contains a label designating the weekday (Monday through Friday), a UISwitch and the following elements that are displayed or hidden respectively based on the state of the switch. If the switch is on, the cell looks like this:

 ----------------------------------------------------------------------
|  Monday    [ON/off]    between        ( N/A )     and       ( N/A )  |
 ----------------------------------------------------------------------

If it's off it looks like this:

 ----------------------------------------------------------------------
|  Monday    [on/OFF]                                                  |
 ----------------------------------------------------------------------

The (N/A) elements are UIButtons. If the user hits one of those buttons a UIPopover with a date picker opens. The idea is that the user selects a time from the picker that should be displayed on the UIButtons instead of the (N/A):

 ----------------------------------------------------------------------
|  Monday    [ON/off]    between      ( 12:30 )     and     ( 16:00 )  |
 ----------------------------------------------------------------------

The hiding of the elements on hitting the UISwitch works as does the display of the popover. However, if the user hits the "Done" button in the popover and the popover is dismissed the app crashes with the following error:

-[UITableViewCell isKindOfClass:]: message sent to deallocated instance 0xf42a100

Strangely enough the only place containing code that calls isKindOfClass is ModalTableViewController (the parent view of the popover and the custom cells) and the address of the instance displayed does not belong to it. Neither is it the address of the popover which only leaves the class of the custom cells (WeekdaySelectionWithPopoverCellController).

Let me give you the relevant parts of the ModalTableViewController.m:

@implementation ModalTableViewController

@synthesize mtvcNavigationBar;
@synthesize mtvcTableView;

@synthesize cell;
@synthesize lable;

@synthesize button;

// WeekdaySelectionWithPopoverCell
@synthesize wswpMainLabel;
@synthesize wswpFromLabel;
@synthesize wswpToLabel;
@synthesize wswpOClockFromLabel;
@synthesize wswpOClockToLabel;
@synthesize wswpSwitch;
@synthesize wswpFromValueButton;
@synthesize wswpToValueButton;

@synthesize popoverController;

// more code...

- (ModalTableViewController *)initWithParam:(NSString *)title andData:(NSArray *)myData andSelection:(NSArray *)selection  {

    [self initSwipeLeftNavigation];

    mtvcNavigationBar.topItem.title = title;

    mtvcSectionSize = [myData count];
    mtvcSectionname = @"";

    mtvcLabels = myData;
    mtvcData   = selection;

    [mtvcLabels retain];
    [mtvcData retain];
    [otherValues retain];

    mtvSingleton = [ModalTableViewSingleton sharedInstance];

    return self;
}

// more code...



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cellRet;

    NSString *MyIdentifier = @"WeekdaySelectionWithPopoverCellController";

    cellRet = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cellRet == nil) {
        [[NSBundle mainBundle] loadNibNamed:MyIdentifier owner:self options:nil];
        cellRet = self.cell;
    }

    NSDictionary *tempValues;
    tempValues = [mtvcData objectAtIndex:indexPath.row];

    wswpSwitch = (UISwitch *)[cellRet viewWithTag:2];
    wswpSwitch.on = [[tempValues valueForKey:@"company_id"] isKindOfClass:[NSNull class]] ? false: true;

    BOOL negatedState = !wswpSwitch.on;

    NSLog(@"tempValues: %@", tempValues);

    lable      = (UILabel *)[cellRet viewWithTag:1];
    lable.text = [NSString stringWithFormat:@"%@", [tempValues valueForKey:@"short"]];
    lable.font = [UIFont boldSystemFontOfSize:16];

    lable        = (UILabel *)[cellRet viewWithTag:3];
    lable.font   = [UIFont boldSystemFontOfSize:16];
    lable.text   = [NSString stringWithFormat:@"%@", @"von"];
    lable.hidden = negatedState;

    lable        = (UILabel *)[cellRet viewWithTag:5];
    lable.text   = [NSString stringWithFormat:@"%@", @"bis"];
    lable.font   = [UIFont boldSystemFontOfSize:16];
    lable.hidden = negatedState;

    lable        = (UILabel *)[cellRet viewWithTag:7];
    lable.text   = @"Uhr";
    lable.font   = [UIFont boldSystemFontOfSize:16];
    lable.hidden = negatedState;

    lable        = (UILabel *)[cellRet viewWithTag:8];
    lable.text   = @"Uhr";
    lable.font   = [UIFont boldSystemFontOfSize:16];
    lable.hidden = negatedState;

    button = (UIButton *)[cellRet viewWithTag:4];
    [self setButtonLabel:button forKey:@"beginning" fromDict:tempValues];
    button.hidden = negatedState;
    /*
    if (![[tempValues valueForKey:@"beginning"] isKindOfClass:[NSNull class]]) {

        button.titleLabel.text = [NSString stringWithFormat:@"%@", [tempValues valueForKey:@"beginning"]];
    } else {
        button.titleLabel.text = @"k.A.";
    }
     */

    button = (UIButton *)[cellRet viewWithTag:6];
    [self setButtonLabel:button forKey:@"until" fromDict:tempValues];
    button.hidden = negatedState;
    /*
    if (![[tempValues valueForKey:@"until"] isKindOfClass:[NSNull class]]) {

        button.titleLabel.text = [NSString stringWithFormat:@"%@", [tempValues valueForKey:@"until"]];
    } else {
        button.titleLabel.text = @"k.A.";
    }
     */

    self.cell = nil;

    return cellRet;
}

- (void)setButtonLabel:(UIButton *)btn forKey:(NSString *)key fromDict:(NSDictionary *)dict {
    [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];

    NSString *text = [dict objectForKey:key];
    if ([mtvSingleton.sharedData obj开发者_如何学PythonectForKey:key]) {
        [btn setTitle:[mtvSingleton.sharedData objectForKey:key] forState:UIControlStateNormal];
    } else {
        if ([text isKindOfClass:[NSNull class]] ||
            [text isEqualToString:@""])
        {
            [btn setTitle:@"k.A." forState:UIControlStateNormal];
        } else {
            [btn setTitle:text forState:UIControlStateNormal];
        }
    }
}

// more code...

- (IBAction)switchButtonValueChanged:(id)sender
{
    //[self changeDisplayState:wsdSwitch.on forObj:sender];
    // UISwitch *tmp = (UISwitch *)sender;
    UIView *v = (UIView *)sender;
    do {
        v = v.superview;
    } while (![v isKindOfClass:[UITableViewCell class]]);
    // WeekdaySelectionWithPopoverCellController *cell1 = (WeekdaySelectionWithPopoverCellController *)v;
    cell = (UITableViewCell *)v;

    wswpSwitch = (UISwitch *)[cell viewWithTag:2];
    BOOL negatedState = !wswpSwitch.on;

    lable = (UILabel *)[cell viewWithTag:3];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell viewWithTag:5];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell viewWithTag:7];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell viewWithTag:8];
    lable.hidden = negatedState;

    button = (UIButton *)[cell viewWithTag:4];
    button.hidden = negatedState;

    button = (UIButton *)[cell viewWithTag:6];
    button.hidden = negatedState;

    /*
    wswpSwitch = (UISwitch *)[cell1 viewWithTag:2];
    BOOL negatedState = !wswpSwitch.on;

    lable = (UILabel *)[cell1 viewWithTag:3];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell1 viewWithTag:5];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell1 viewWithTag:7];
    lable.hidden = negatedState;

    lable = (UILabel *)[cell1 viewWithTag:8];
    lable.hidden = negatedState;

    button = (UIButton *)[cell1 viewWithTag:4];
    button.hidden = negatedState;

    button = (UIButton *)[cell1 viewWithTag:6];
    button.hidden = negatedState;
     */

}

#pragma mark - handlers

- (IBAction)toButtonHandler:(id)sender {
    dppvc = [[DatePickerPopoverViewController alloc] initWithCaller:self andKey:@"beginning"];
    UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:dppvc];

    popover.delegate = self;
    self.popoverController = popover;
    [popover release];

    [self.popoverController presentPopoverFromRect:[(UIButton *)sender frame]
                                            inView:self.view
                          permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

- (IBAction)fromButtonHandler:(id)sender {
    dppvc = [[DatePickerPopoverViewController alloc] initWithCaller:self andKey:@"until"];
    UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:dppvc];

    popover.delegate = self;
    self.popoverController = popover;
    [popover release];

    CGRect senderFrameRect = [(UIButton *)sender frame];

    [self.popoverController presentPopoverFromRect:senderFrameRect
                                            inView:self.view
                          permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}


#pragma mark - UIPopoverControllerDelegate

//---called when the user clicks outside the popover view---
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {

    // NSLog(@"popover about to be dismissed");
    return YES;
}

//---called when the popover view is dismissed---
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {

    // NSLog(@"popover dismissed");    
}

- (void)dismissPopover {
    if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];

        NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
        int i;
        for (i = 0; i < [mtvcLabels count]; i++) {
            [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
        }

        [mtvcTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:YES];
    }
}

- (void)dealloc {
    [mtvcSectionname release];
    [mtvcLabels      release];
    [mtvcData        release];

    [cell      release];

    [super dealloc];
}

The crash occurs in main.m:

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // crashes:
    int retVal = UIApplicationMain(argc, argv, nil, nil);        // <--

    [pool release];
    return retVal;
}

I have enabled NSZombieEnabled, MallocStackLoggingNoComp and NSAutoreleaseFreedObjectCheckEnabled but the compiler doesn't give me any more information than what I posted.

I've spent the entire day trying to resolve this but to no avail. Any hint in the right direction is appreciated!


I've been able to take care of this particular error. The problem was that cellRet in cellForRowAtIndexPath had not been retained. The following snippet resolves the error mentioned above:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cellRet;

    NSString *MyIdentifier = @"WeekdaySelectionWithPopoverCellController";

    cellRet = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cellRet == nil) {
        [[NSBundle mainBundle] loadNibNamed:MyIdentifier owner:self options:nil];
        cellRet = self.cell;
        [cellRet retain];
    }

    // ...
}

Now however, I'm stuck with a new, similar error. This time it says:

*** -[CALayer release]: message sent to deallocated instance 0xc656d30

The following topic has some more information on the problem: "[CALayer release]: message sent to deallocated instance" when dismissing modal view controller

I have tried to change the property of the popover view controller to assign instead of retain but that gave me the message sent to deallocated instance error again, this time for the popover view controller.

Somebody with an idea? TIA!


The way I usually handle this is to create a subclass of UITableViewCell for my custom cells. and use the nib. I create a custom init that loads the cell from the nib. as follows.

- (id)init
    {
    self = [[[[NSBundle mainBundle] loadNibNamed:@"NibName" owner:self options:nil] objectAtIndex:0] retain];
    if (self) 
        {
        // any further initialization
        }
    return self;
    }

in the nib set the cell's class to your new class.

then to use your cell do the following.

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (!cell)
      {
      cell = [[[CustomCell alloc] init] autorelease];
      }
  // setup your cell
return cell;
}

You should definitely be using assign on your delegate properties.

0

精彩评论

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

关注公众号