6

Update 2, I hope this helps someone, there is a solutions at the following link: https://discussions.apple.com/thread/5498630?start=0&tstart=0 , evidently this is an iOS bug and this work around works. I can create the new sharedPicker, but I cannot get anything from it or dismiss it, I'm not sure how to format beyond what is supplied at the link Any help on that is very welcome.

So my question now is how to take the following code and actually create the code for peoplePickerNavigationControllerDidCancel: and peoplePickerNavigationController:shouldContinueAfterSelectingPerson: Thanks. I've left most of my original post in case someone has a similar vague issue.

// Convoluted workaround for the iPhone 4S crash
+ (ABPeoplePickerNavigationController *)sharedPeoplePicker {
    static ABPeoplePickerNavigationController *_sharedPicker = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedPicker = [[ABPeoplePickerNavigationController alloc] init];
    });
    return _sharedPicker;
}
// then later on, use 
[YourController sharedPeoplePicker].delegate = self;
// etc.

My current code:

- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    [self displayPerson:person];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
    return NO;

}
- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{

    //[self dismissViewControllerAnimated:YES completion:nil];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)pick1:(id)sender
{
    ABPeoplePickerNavigationController *picker1 =[[ABPeoplePickerNavigationController alloc] init];
    picker1.peoplePickerDelegate = self;

    [self presentViewController:picker1 animated:YES completion:nil];

    x=1;
}

Update 1, this app crashes on iPhone 4/4s, but runs in the simulator and iPhone5 if that means anything. I'm thinking its just they have enough power to get past whatever leak I have created

I have an iOS app with a view controller where the user can chose contacts for the app using ABPeoplePickerNavigationController or enter numbers manually. If numbers are entered manually there are no issues. If the user opens and:

  1. Picks a new contact from the address book

  2. Updates a contact from the address book to use in the app

  3. Opens and cancels the address book (all without saving the action)

Then I cannot navigate to one particular view in my app without a crash. I am at a loss why I cannot go to this one view controller, or why it causes the crash.

I am using 5 different pickers, one for each contact I want to add and potentially save. I save as NSUserDefaults, but like I said, the crash persists even if the picker selection is never saved. I can navigate to all view in the app from a sidebar navigation without incident, the only thing different about the view I fail on is that it is presented from one of the main view controllers and not my sidebar.

I appreciate any help or thoughts. This was the first app I wrote and I'm trying to update it and failing. I want to get it functional again so I can come back and refactor it.

My implementation:

    - (IBAction)pick1:(id)sender
{
    ABPeoplePickerNavigationController *picker1 =
    [[ABPeoplePickerNavigationController alloc] init];
    picker1.peoplePickerDelegate = self;

    [self presentViewController:picker1 animated:YES completion:nil];
    x = 1;
}
- (IBAction)pick2:(id)sender
{
    ABPeoplePickerNavigationController *picker2 =
    [[ABPeoplePickerNavigationController alloc] init];
    picker2.peoplePickerDelegate = self;

    [self presentViewController:picker2 animated:YES completion:nil];
    x=2;
}
- (IBAction)pick3:(id)sender
{
    ABPeoplePickerNavigationController *picker3 =
    [[ABPeoplePickerNavigationController alloc] init];
    picker3.peoplePickerDelegate = self;

    [self presentViewController:picker3 animated:YES completion:nil];
    x=3;
}
- (IBAction)pick4:(id)sender
{
    ABPeoplePickerNavigationController *picker4 =
    [[ABPeoplePickerNavigationController alloc] init];
    picker4.peoplePickerDelegate = self;

    [self presentViewController:picker4 animated:YES completion:nil];
    x=4;
}
- (IBAction)pick5:(id)sender
{
    ABPeoplePickerNavigationController *picker5 =
    [[ABPeoplePickerNavigationController alloc] init];
    picker5.peoplePickerDelegate = self;

    [self presentViewController:picker5 animated:YES completion:nil];
    x=5;
}
- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{
    [self dismissViewControllerAnimated:YES completion:nil];
}


- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    [self displayPerson:person];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];


    return NO;
}

- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    return NO;
}
- (void)displayPerson:(ABRecordRef)person
{
    NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
                                                                    kABPersonFirstNameProperty);


    NSString* phone = nil;
    ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
                                                     kABPersonPhoneProperty);
    if (ABMultiValueGetCount(phoneNumbers) > 0) {
        phone = (__bridge_transfer NSString*)
        ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
    } else {
        phone = @"[None]";
    }
    if (x==1){
        firstName1.text = name;
        contact1.text = phone;
    }
    if (x==2){
        firstName2.text = name;
        contact2.text = phone;
    }
    if (x==3){
        firstName3.text = name;
        contact3.text = phone;
    }
    if (x==4){
        firstName4.text = name;
        contact4.text = phone;
    }
    if (x==5){
        firstName5.text = name;
        contact5.text = phone;
    }

}
Greg Bew
  • 111
  • 6
  • And where exactly is it crashing ? Probably you are not retaining some variables. – Grzegorz Krukowski Nov 22 '13 at 14:29
  • If I edit this code out, my app runs fine, it just requires manual entering of phone numbers. As far as debugging I get an F, I can't understand anything Xcode says and all I get now is an lldb. I will go back through and verify my saving, but what kills me is I use one method to save no matter the entry method, and even if I just bring up the picker view and don't save, I can cancel it, my app will still crash when I go the this one specific view. – Greg Bew Nov 22 '13 at 21:41
  • More information: I have a series of view controllers embedded in a navigation controller. From the home screen I can navigate anywhere without issue. If I open the PeoplePicker on my contacts view controller, then go back home to initiate contact, my app crashes. This happens regardless of action taken with the PeoplePicker. When I reopen the app, it will function fine on all screens until I open PeoplePicker again? Is this some view release issue? – Greg Bew Nov 22 '13 at 21:57
  • Just add exception breakpoint and see where it crashes. Paste a code / function class where it crashed – Grzegorz Krukowski Nov 22 '13 at 22:34
  • int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } – Greg Bew Nov 23 '13 at 15:21
  • libobjc.A.dylib`objc_msgSend: – Greg Bew Nov 23 '13 at 15:22
  • Ok, this one looks more useful. 013-11-23 13:52:31.606 EmergencyAlert[4063:60b] -[OS_xpc_connection barStyle]: unrecognized selector sent to instance 0x14799c30 2013-11-23 13:52:31.612 EmergencyAlert[4063:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[OS_xpc_connection barStyle]: unrecognized selector sent to instance 0x14799c30' libc++abi.dylib: terminating with uncaught exception of type NSException – Greg Bew Nov 23 '13 at 18:53
  • Since `barStyle` is a property of a UITabBar rather than whatever was at that memory address when you got the error, something is likely being released too soon. To see what it is, I suggest editing your build scheme to use zombies. – Phillip Mills Nov 24 '13 at 17:21
  • I did have a TabBar in the app and removed it, I will look for references of that. I used zombies and didn't find anything useful, however I might just not have looked through thoroughly enough. Heres to getting something successful – Greg Bew Nov 24 '13 at 18:54
  • Updated original post, found fix for iOS bug, but can't implement the workaround myself, too rookie for it without an example – Greg Bew Nov 24 '13 at 21:31
  • Has this been filed as a radar with Apple? https://bugreport.apple.com ? (Also if you do, please duplicate it at http://openradar.appspot.com) – Scott Corscadden Mar 25 '14 at 12:26

3 Answers3

3

Sorry to answer my own question, but another work around to this that requires little change is to use CF Retain to correct the over release I was experiencing. I retained the person and the peoplePicker and all was resolved. Thanks for everyone who tried to help me solve this.

- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{

    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
   CFRetain((__bridge CFTypeRef)(peoplePicker));
}
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    [self displayPerson:person];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
    CFRetain(person);
    CFRetain((__bridge CFTypeRef)(peoplePicker));
    return NO;

}
Greg Bew
  • 111
  • 6
  • 1
    With the caveat that it'll leak once the underlying bug is fixed, yes? The singleton workaround presumably avoids that issue. – JLundell Dec 21 '13 at 17:38
1

Thank You for the work around this issue. Your method #2 really works!!! I have the similar situation discussed in https://discussions.apple.com/thread/5498630?start=0&tstart=0 : MKMapView is placed by IB in storyboard, no code except IBOutlet. I present ABPeoplePickerController then simply cancel it by dismiss and leave this view by navigation. Then return back and get memory issue: called method barStyle of zombie UINavigationBar at address of dismissed ABPeoplePickerController. This situation happened only on iOS 7 (iPad 3rd ten and iPhone 4S) but code works fine on iOS 6 (iPhone 3GS) and only with combination with MKMapView. I test with WebView instead of MapView and all works fine. I think it is real bug in iOS 7. Kind regards Alexey

0

Well, there is also a bit more simple solution to this. The actual problem is in using ABPeoplePickerNavigationController as a singleton object, setting its delegate to a view controller and then dismissing the view controller. So, in my case the solution that worked is this one:

- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{
    peoplePicker.peoplePickerDelegate = nil; // clear delegate prior to dismissing self
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}

- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    [self displayPerson:person];
    peoplePicker.peoplePickerDelegate = nil; // clear delegate prior to dismissing self
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
    return NO;
}
oradyvan
  • 301
  • 5
  • 15