0

2 つのタブを持つ UITabBarController があります。TAB A は UIViewController で、TAB B は nib からロードされた UIViewController です。

TAB B から TAB A に移動したとき、または TAB B から他のタブに移動したときに、TAB B を初期状態にリセットしたいと考えています。これを行うには、新しいものを作成し、それを viewControllers 配列で置き換えます。問題は、UIViewController をリセットした後、「メッセージが割り当て解除されたインスタンスに送信されました。通常、次の 2 つのエラーのいずれかです。

*** -[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 を参照するコードは何もありません。また、例外ブレークポイントを追加しようとしましたが、それは一連の 16 進データをリストするだけで、デフォルトでアプリケーションのメインになります。ここに私のログがあります:

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 がオブジェクトに対して追加のリリースを実行しています。

編集:回避策を見つけました。別の UIViewController を tabBarController と TAB B の UIViewController の間に配置しました。その後、新しい UIViewController で古いものをリセットしました。それは機能しますが、物事を行う正しい方法ではありません。そして、何が余分なリリースを引き起こしたのかはまだわかりません。

4

2 に答える 2

0

問題は、1 つのビュー コントローラーを置き換える新しい配列 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 に答える