0

我有一个带有两个选项卡的 UITabBarController。TAB A 是 UIViewController,TAB B 是从 nib 加载的 UIViewController。

我试图让当我从 TAB B 移动到 TAB A 或从 TAB B 任何其他选项卡时,我想将 TAB B 重置为其初始状态。我通过创建一个新的并在 viewControllers 数组中替换它来做到这一点。问题是,在我重置 UIViewController 后,我收到一条错误消息,类似于“发送到已释放实例的消息。它通常是以下两个错误之一:

*** -[AddCompetitionViewController isEqual:]: message sent to deallocated instance...
*** -[AddCompetitionViewController retain]: message sent to deallocated instance...

这发生在我从 TAB B 切换回 TAB A 之后。

这是我用来替换选项卡并尝试隔离问题的代码。

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    NSLog(@"Should Select: %@", viewController);
    return YES;
}

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
    NSLog(@"Did Select: %@", viewController);
    if ([viewController class] != [AddCompetitionViewController class]) {
        AddCompetitionViewController *ACViewController = [[AddCompetitionViewController alloc] initWithNibName:@"AddCompetition" bundle:[NSBundle mainBundle] andDancer:self.currentDancer];
        UITabBarItem *ACitem = [[UITabBarItem alloc] initWithTitle:@"Add Comp." image:[UIImage imageNamed:@"Addcomp.png"] tag:0];
        ACViewController.tabBarItem = ACitem;

        NSMutableArray *arr = [[NSMutableArray alloc] initWithArray:self.viewControllers];
        [arr replaceObjectAtIndex:1 withObject:ACViewController];
        [self setViewControllers:arr];
        NSLog(@"Replaced: %@", [arr objectAtIndex:1]);
    }
}

(我正在使用 ARC)

使用 NSLogs,我已经能够确定当我尝试切换回 TAB A 时,应用程序正在尝试引用旧的、原始的 UIViewController,而不是新的。tabBarController:didSelectViewController: 是最后一个被调用的东西,我没有任何代码在替换后引用 UIViewController。我也尝试添加一个异常断点,但它只列出了一堆十六进制数据,然后默认为应用程序主。这是我的日志:

2012-08-18 16:20:05.479 How's My Feisin'[4780:c07] Should Select: <AddCompetitionViewController: 0x78a5af0>
2012-08-18 16:20:05.489 How's My Feisin'[4780:c07] Did Select: <AddCompetitionViewController: 0x78a5af0>
2012-08-18 16:20:06.885 How's My Feisin'[4780:c07] Should Select: <CompetitionListViewController: 0x78a7550>
2012-08-18 16:20:06.887 How's My Feisin'[4780:c07] Did Select: <CompetitionListViewController: 0x78a7550>
2012-08-18 16:20:06.887 How's My Feisin'[4780:c07] Replaced: <AddCompetitionViewController: 0x6c5d0f0>
2012-08-18 16:20:09.290 How's My Feisin'[4780:c07] *** -[AddCompetitionViewController retain]: message sent to deallocated instance 0x78a5af0

和回溯:

* thread #1: tid = 0x1c03, 0x017cddee CoreFoundation`___forwarding___ + 206, stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
frame #0: 0x017cddee CoreFoundation`___forwarding___ + 206
frame #1: 0x017cdcb2 CoreFoundation`_CF_forwarding_prep_0 + 50
frame #2: 0x0176e2c0 CoreFoundation`CFRetain + 96
frame #3: 0x01798ab9 CoreFoundation`CFArrayApplyFunction + 57
frame #4: 0x0072ffbb UIKit`_afterCACommitHandler + 255
frame #5: 0x0183b99e CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
frame #6: 0x017d2640 CoreFoundation`__CFRunLoopDoObservers + 384
frame #7: 0x0179e4c6 CoreFoundation`__CFRunLoopRun + 1174
frame #8: 0x0179dd84 CoreFoundation`CFRunLoopRunSpecific + 212
frame #9: 0x0179dc9b CoreFoundation`CFRunLoopRunInMode + 123
frame #10: 0x01c447d8 GraphicsServices`GSEventRunModal + 190
frame #11: 0x01c4488a GraphicsServices`GSEventRun + 103
frame #12: 0x0071f626 UIKit`UIApplicationMain + 1163
frame #13: 0x00002595 How's My Feisin'`main + 181 at main.m:16
frame #14: 0x000024d5 How's My Feisin'`start + 53

任何帮助找出这个错误,或者找到一个更好的地方来替换 UIViewController 都会很棒!谢谢!

编辑:我找到了导致问题的原因,但仍然没有办法解决它。尽管我从未见过 UITabBarController 为视图更改设置动画,但它显然仍会执行动画。我设法分析了应用程序,并且 _afterCACommitHandler 正在对该对象进行额外的发布。

编辑:我想出了一个解决方法,我在 tabBarController 和 TAB B 的 UIViewController 之间放置了另一个 UIViewController。然后让新的 UIViewController 重置旧的。它有效,但它不是做事的正确方法。而且我仍然不知道是什么导致了额外的释放。

4

2 回答 2

0

我认为问题在于您创建了一个新数组 arr,在其中替换了一个视图控制器,但您从未将选项卡栏控制器的 viewControllers 数组重置为该数组。在 [arr replaceObjectAtIndex:1] 语句之后,尝试添加以下行:

tabBarController.viewControllers = arr;

于 2012-08-18T21:36:13.853 回答
0

我创建了一个解决方法,将 TAB B 的 UIViewController 封装在另一个 UIViewController 中。这个中间控制器是 UITabBarController 的委托,它会释放并重新创建我想要在选项卡更改时重置的 UIViewController。这可以防止标签栏控制器中缺少 ViewController 引用。

这是中间类:

.h 文件

#import <UIKit/UIKit.h>
#import "AddCompetitionViewController.h"
#import "Dancer.h"

@interface AddCompResetViewController : UIViewController <UITabBarControllerDelegate>
{
    BOOL willReset;
}

@property (nonatomic, retain) Dancer *currentDancer;
@property (nonatomic, retain) AddCompetitionViewController *ACViewController;

- (id)initWithDancer:(Dancer *)dancer andTabBarController:(UITabBarController *)aController;
@end

.m 文件

@implementation AddCompResetViewController
@synthesize currentDancer, ACViewController;

- (id)initWithDancer:(Dancer *)dancer andTabBarController:(UITabBarController* )aController;
{
    if ((self = [super init])) {
        self.currentDancer = dancer;
        //create first instance
        self.ACViewController = [[AddCompetitionViewController alloc] initWithNibName:@"AddCompetition" bundle:[NSBundle mainBundle] andDancer:self.currentDancer];
        self.ACViewController.theTabBarController = aController;
        [self.view addSubview:self.ACViewController.view];
        willReset = NO;
    }
    return self;
}

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
    //reset
    if (viewController != self) {
        AddCompetitionViewController *AViewController = [[AddCompetitionViewController alloc] initWithNibName:@"AddCompetition" bundle:[NSBundle mainBundle] andDancer:self.currentDancer];
        [self.ACViewController.view removeFromSuperview];
        self.ACViewController = nil;
        self.ACViewController = AViewController;
        [self.view addSubview:self.ACViewController.view];
        willReset = NO;
    } else if (viewController == self) {
        willReset = YES;
    }
}

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    if (viewController.tabBarItem.tag == 4) {
        [self.navigationController popToRootViewControllerAnimated:YES];
        return NO;
    } else {
        return YES;
    }
}
于 2012-10-03T02:33:37.460 回答