1

(注:以前、プロジェクトのコンテキストでこの質問を提出しましたが、テストプロジェクトでクラッシュを再現しました。間違っていることを教えてくれると助かります。)

別のモーダルビューコントローラーからABPeoplePickerを呼び出すと、クラッシュが発生します。具体的には、メインウィンドウにはmyVCをロードするNavControllerがあります。次に、myVCは、コントローラーを含むモーダルNavControllerをロードし、ABPeoplePickerを呼び出します。このデモプログラムでは、ABPeoplePickerが実行されるまでユーザーの介入は必要ありません。

ピープルピッカーの検索ボックスを使用して、結果のピープルの1つを選択すると、クラッシュが発生します。(シミュレーターを使用する場合は、プログラムを実行する前に連絡先に人を追加する必要があります。)プログラムは戻りますが、2つのモーダルVCの却下中に、アサーションエラーがクラッシュします。これは、iphone、ipad、および両方のシミュレーターで毎回発生します。これはごく普通のことのように思われるので、これが本当のバグであるとは信じがたいです。クラッシュメッセージは次のとおりです。

-[ABMembersSearchDisplayController setActive:animated:]、/SourceCache/UIKit_Sim/UIKit-1448.69/UISearchDisplayController.m:589 2011-01-31 13:51:11.903 testcrasher2 [26044:207]でのアサーションの失敗* キャッチされなかった例外のためにアプリを終了しています ' NSInternalInconsistencyException'、理由:'検索コンテンツナビゲーションコントローラーは、-setActive:YESと-setActive:NOの間で変更してはなりません'

そのため、新しいXcode iPhone Windowアプリケーションで、didFinishLaunchingWithOptionsを変更してコントローラーを呼び出します。次に、次のように2つのVCを作成します。(ターゲットにアドレスブックフレームワークを追加する必要があることに注意してください。)プログラム全体は次のとおりです...

AppDelegate.didFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    myViewController *detailViewController = [[myViewController alloc] init];

    // Set the navigation controller as the window's root view controller and display.
    UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController: detailViewController];

    self.window.rootViewController = navController;
    [self.window makeKeyAndVisible];

    [detailViewController release];
    [navController release];

    return YES;
}

myViewController.h:

@interface myViewController :  UIViewController<addDelegate>{
 }
@end

myViewController.m:

#import "myViewController.h"
#import "AddNewViewController.h"        

@implementation myViewController

- (void)controllerDidFinish:(addNewViewController *)controller  {
    [self dismissModalViewControllerAnimated:YES];
}

-(void) viewWillAppear:(BOOL)animated  {
    [super viewWillAppear: animated];

    addNewViewController *addController = [[addNewViewController alloc] init];
    addController.delegate = self;

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addController];
    [self presentModalViewController:navController animated:YES];

    [navController release];
    [addController release];
}

@end

AddNewViewController.h:

#import <AddressBookUI/AddressBookUI.h>

@protocol addDelegate;

@interface addNewViewController : UIViewController  < ABPeoplePickerNavigationControllerDelegate> {
    id <addDelegate> delegate;  
}
    @property(nonatomic, assign) id <addDelegate> delegate;
@end


@protocol addDelegate <NSObject> 
    - (void)controllerDidFinish:(addNewViewController *)controller ; 
@end

AddNewViewController.m:

#import "AddNewViewController.h"

@implementation addNewViewController

@synthesize delegate;

-(void) viewDidAppear:(BOOL)animated {  
    ABPeoplePickerNavigationController * peoplepicker =  [[ABPeoplePickerNavigationController alloc] init] ;    
    peoplepicker.peoplePickerDelegate = self;
    [self presentModalViewController:peoplepicker animated:YES];
    [peoplepicker release];
}

#pragma mark AddressBook delegate methods

- (void)peoplePickerNavigationControllerDidCancel: (ABPeoplePickerNavigationController *)peoplePicker { 
    [self dismissModalViewControllerAnimated:YES];
}

- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person {
    [self.delegate controllerDidFinish:self ];  
    return NO;   //EDIT:  This MUST be YES or it will crash (see answer below)
}

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker 
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
      property:(ABPropertyID)property 
      identifier:(ABMultiValueIdentifier)identifier {
    return NO;
}

@end
4

2 に答える 2

2

これは実際のバグであることが判明しました。ユーザーが検索中の人をクリックしたときにABPeoplePickerに対して二重のModalVC却下を行うと、このクラッシュが発生することは確かです。幸い、簡単な回避策があります。デリゲートのshouldContinueAfterSelectingPersonでYESを返します。ピッカーを同時に閉じるので、YESを返すかNOを返すかは実際には問題ではなく、続行されませんが、NOはクラッシュし、YESはクラッシュしません。(私の元の投稿と同じ答え:ABPeoplePickerでの奇妙なクラッシュ

于 2011-02-18T00:56:27.563 に答える
1

バグは実際にはあなたのコードにあります。見つけるのに数分かかりました。できる限り説明します。

  1. あなた ABPeoplePickerNavigationController は現在、モーダルで表示されています。
  2. 検索バーをクリックして、何かを入力します。
  3. 人の名前をクリックします。

ここで何が起こるかというと、 はABPeoplePickerNavigationControllerデリゲート (あなたのaddNewViewController) に人を選択した後に続行するかどうかを尋ねます。あなたからの返事を待っている間に、あなたは突然、独自のプロトコルのメソッド ( 内myViewController) を呼び出して、 modal を却下しようとしaddNewViewControllerます。ABPeoplePickerNavigationControllerはまだ開いているので、あなたは自分より先にジャンプしています。

ABPeoplePickerNavigationControllerDelegate メソッドの実装を次のように変更します。

- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person {
    // This line is new.
    [self.navigationController dismissModalViewControllerAnimated:YES];
    [self.delegate controllerDidFinish:self];
    return NO;
}

そして、あなたのクラッシュはなくなります。UIViewControllers と UINavigationControllers のレイヤー上のレイヤーを扱っているときは、提示した逆の順序でそれらを破棄するように十分に注意する必要があります。

于 2011-02-01T00:56:37.183 に答える