消息发送到解除分配的实例(可能是UITableViewCell)

时间:2011-08-31 15:08:20

标签: objective-c xcode ipad memory-management

我知道很多人以前都遇到过这个问题,我已经阅读了很多建议的解决方案,其中没有一个能为我解决。我正在处理一个大型项目的一部分,涉及三个不同的视图:第一个视图包含一个UITableView,其中包含名为WeekdaySelectionWithPopoverCellController的自定义单元格。此单元格包含指定工作日(周一至周五)的标签,UISwitch以及根据交换机状态分别显示或隐藏的以下元素。如果开关打开,则单元格如下所示:

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

如果它关闭它看起来像这样:

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

(N / A)元素是UIButtons。如果用户点击其中一个按钮,则会打开带有日期选择器的UIPopover。我们的想法是用户从选择器中选择应该显示在UIButtons上的时间而不是(N / A):

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

在击中UISwitch时隐藏元素的工作方式与弹出窗口的显示一样。但是,如果用户点击弹出窗口中的“完成”按钮并且弹出窗口被解除,则应用程序崩溃并出现以下错误:

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

奇怪的是,包含调用isKindOfClass的代码的唯一地方是ModalTableViewController(弹出窗口的父视图和自定义单元格),并且显示的实例的地址不属于它。它也不是只留下自定义单元格类(WeekdaySelectionWithPopoverCellController)的弹出窗口的地址。

让我给你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 objectForKey: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];
}

崩溃发生在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;
}

我已启用NSZombieEnabledMallocStackLoggingNoCompNSAutoreleaseFreedObjectCheckEnabled但编译器不会向我提供比我发布的信息更多的信息。

我花了一整天时间试图解决这个问题,但无济于事。任何正确方向的提示都值得赞赏!

2 个答案:

答案 0 :(得分:0)

我已经能够处理这个特殊的错误。问题是cellRet中的cellForRowAtIndexPath未被保留。以下代码段解决了上述错误:

- (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];
    }

    // ...
}

然而,现在,我遇到了一个类似的新错误。这次它说:

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

以下主题提供了有关此问题的更多信息:"[CALayer release]: message sent to deallocated instance" when dismissing modal view controller

我尝试将popover视图控制器的属性更改为assign而不是retain,但这又给了message sent to deallocated instance错误,这次是对于popover视图控制器。 / p> 有人有想法吗? TIA!

答案 1 :(得分:0)

我通常处理的方法是为我的自定义单元格创建UITableViewCell的子类。并使用笔尖。我创建了一个从笔尖加载单元格的自定义init。如下。

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

将单元格的类设置为新类。

然后使用您的手机执行以下操作。

  - (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;
}

您绝对应该在委托属性上使用assign。