当从另一个模态视图控制器调用时,ABPeoplePicker崩溃并且都被解雇了

时间:2011-01-31 22:10:06

标签: iphone abpeoplepickerview

(注意:我之前在项目的上下文中提交了这个问题,但我现在已经在测试项目中重新创建了崩溃。任何帮助告诉我我做错了什么都会受到赞赏。)

从另一个模态viewcontroller调用ABPeoplePicker时发生崩溃。具体来说,主窗口有一个NavController,它加载myVC。 myVC然后加载一个包含我的控制器的模态NavController,然后调用ABPeoplePicker。在此演示程序中,在ABPeoplePicker运行之前,无需用户干预。

如果您使用人员选择器中的搜索框,然后选择其中一个结果人员,则会发生崩溃。 (如果你使用模拟器,你需要在运行程序之前在Contacts中添加一个人。)程序返回,但在解雇两个模态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来调用我的控制器。然后我按如下方式创建两个VC。 (注意,您需要将Addressbook框架添加到目标。)这是整个程序......

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

2 个答案:

答案 0 :(得分:2)

原来这是一个真正的错误。确实如果你在用户点击搜索中的某个人时对你的ABPeoplePicker进行双重ModalVC解雇,你就会遇到这种崩溃。幸运的是,有一个简单的解决方法:在委托中输入YESContinueAfterSelectingPerson。当你同时解雇选择器时,无论你返回YES还是NO都没关系,它不会继续,但是NO会崩溃,YES则不会。 (与我原来的帖子答案相同:Weird crash in ABPeoplePicker

答案 1 :(得分:1)

该错误实际上在您的代码中。花了几分钟才找到它,我会尽力解释。

  1. ABPeoplePickerNavigationController 目前以模态呈现。
  2. 您点击搜索栏并输入 一些东西。
  3. 您点击了某个人的姓名。
  4. 这里发生了什么,是ABPeoplePickerNavigationController询问其代表(您的addNewViewController)是否应该在选择一个人后继续。在等待您回复的同时,您突然调用自己的协议方法(在myViewController中)尝试关闭模式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层上处理图层时,你必须非常小心地按照你提出的相反顺序来解雇它们。