【问题标题】:Crash in ABPeoplePicker when called from another modal viewcontroller and both dismissed从另一个模态视图控制器调用时 ABPeoplePicker 崩溃并且两者都被解雇
【发布时间】:2011-01-31 22:10:05
【问题描述】:

(注意:我之前在我的项目的上下文中提出了这个问题,但我现在已经在一个测试项目中重新创建了崩溃。任何帮助告诉我我做错了什么将不胜感激。)

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

如果您使用人员选择器中的搜索框,然后选择结果人员之一,则会发生崩溃。 (如果您使用模拟器,则需要在运行程序之前在联系人中添加一个人。)程序返回,但在两个模态 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,如下所示。 (请注意,您需要将地址簿框架添加到目标。)这是整个程序...

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

【问题讨论】:

    标签: iphone abpeoplepickerview


    【解决方案1】:

    原来这是一个实际的错误。确实,如果您在用户单击搜索中的人时对 ABPeoplePicker 执行双重 ModalVC 关闭,您将遇到此崩溃。幸运的是,有一个简单的解决方法:在您的委托的 shouldContinueAfterSelectingPerson 中返回 YES。当您同时关闭选择器时,返回 YES 或 NO 并不重要,它不会继续,但 NO 会崩溃而 YES 不会。 (与我原来的帖子相同的答案:Weird crash in ABPeoplePicker

    【讨论】:

    • Apple 告诉我这已在 5.0 中修复
    【解决方案2】:

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

    1. 你的 ABPeoplePickerNavigationController 目前以模态呈现。
    2. 您在搜索栏中单击并键入 一些东西。
    3. 你点击一个人的名字。

    这里发生了什么,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 时,你必须非常小心地按照你呈现它们的相反顺序来关闭它们。

    【讨论】:

    • 所以我把它放进去,崩溃确实消失了。在父级的dismissModalVC(在controllerDidFinish 中)期间,它确实抱怨了两次“尝试关闭其视图当前未出现的模态视图控制器。”所以,我把那个拿出来了,它工作得很好。非常感谢。
    • 但是,我不完全理解,正如 Apple 的文档所说“例如,如果用户取消当前操作,您可以通过关闭第一个模态呈现的视图控制器来删除链中的所有对象。换句话说,解除模态视图控制器不仅会解除该视图控制器,还会解除它以模态方式呈现的任何视图控制器。”那么,父母的解雇不应该对他们俩都合适吗?
    • 所以……说得很快。删除父母的dismissModalVC意味着我不会弹出它,只是弹出孩子的。但是随后取消(父母解雇)然后起作用了。把它放回去,我得到了那些“试图解雇”。所以...作为一种解决方法,我输入了“[self performSelector: @selector(dismissModalVC) withObject:nil afterDelay:0.5];”允许孩子在父母也被解雇之前解雇。丑陋,但它似乎工作。
    • @Craig,还有什么想法吗?
    • @mackworth 进一步的想法是什么意思?以与您呈现它们相反的顺序移除导航控制器是否解决了问题?我阅读了您对 Apple 文档的评论,但我认为您可能希望通过电子邮件向他们发送有关此特定问题的信息。我相信他们会帮助你。
    猜你喜欢
    • 2017-09-10
    • 2011-11-21
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2011-06-21
    相关资源
    最近更新 更多