0

The scenario is that I have more than one view that wants to invoke the Address Book. So as not to duplicate the code of the delegate in each view I have located the code in the App Delegate's header and .m file, but using an "@interface AddressBookDelegate" and "@implementation AddressBookDelegate" at the bottom of the 2 respective App Delegate fiies-

@interface AddressBookDelegate : UIViewController <ABPeoplePickerNavigationControllerDelegate> {
AddressBookDelegate *addressBookDelegate;   
}
@property (nonatomic, retain) AddressBookDelegate *addressBookDelegate;
@end

and

@implementation AddressBookDelegate
@synthesize addressBookDelegate;

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

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{   
    [super dismissModalViewControllerAnimated:YES];

    ...get stuff from the Address Book...   

    return NO;
}

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

Then in my views I have the following code:

addressBookDelegate = (AddressBookDelegate *) [[UIApplication sharedApplication] delegate];

ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc]init];    
abPicker.peoplePickerDelegate = self.addressBookDelegate;
[self presentModalViewController:abPicker animated:YES];
[abPicker release];

The Address Book displays fine in all views. But when I take any user action that would invoke a delegate, like the Address Book's Cancel button, I crash-

-[MyprogAppDelegate peoplePickerNavigationControllerDidCancel:]: unrecognized selector sent to instance

It compiles clean, no Warnings.

How do I wire-up the peoplePickerDelegate to connect to the Address Delegate code when it is not physically in the same file as the view itself ? Thx.

ADDED NOTE: when I use the debugger and stop on the line

abPicker.peoplePickerDelegate = addressBookDelegate;

in the view code, I see that the address for the addressBookDelegate is stated to be the address of the MyprogAppDelegate, not AddressBookDelegate as I might have expected. That makes me think the displacement to the address book delegate code is off within the App Delegate file.

If the AddressBookDelegate Cancel Delegate code were say 1000 bytes into the AddressBookDelegate, my app is actually "entering" the code 1000 bytes into MyprogAppDelegate, and so crashes. So somehow I am not setting up the addressing of the AddressBookDelegate correctly. That's my take on it anyway...

Ric
  • 796
  • 12
  • 28

3 Answers3

1

Your code assumes that your appdelegate (MyprogAppDelegate) implements method peoplePickerNavigationControllerDidCancel.

So, your code in MyprogAppDelegate should be something like this:

@implementation MyprogAppDelegate
@synthesize ...;

#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    


    return YES;
}

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

}
beryllium
  • 29,669
  • 15
  • 106
  • 125
  • it has it, sorry, I assumed that was apparent. I've added it to the question. So the people picker delegate code located in the App Delegate IS there. There is something awry in my addressing it, connecting to it. Pls note the added text at the bottom of the question in case that clarifies anything. – Ric Dec 02 '11 at 19:18
0

EDIT Okay, the entire first answer has been tossed out. This is, with some warning, still a bit of a shot in a dark, but I think it's going to be closer to helpful. Some of the ideas do carry over though.

  1. You very probably don't need a separate class to act as your ABPeoplePickerNavigationControllerDelegate. In all likelihood, it should be the same class that has your code at the bottom (that calls presentModalViewController:animated:. Since I don't know what controller that was, I'm going to just call it MyViewController for reference. The reason you want that view controller to be the delegate is because, in your delegate methods, you need to be able to dismiss the modal view controller that has the address book.

  2. You definitely don't want the your program's UIApplicationDelegate to be the ABPeoplePickerNavigationControllerDelegate. As you said yourself, peoplePickerDelegate has to be a UIViewController.

So, to MyViewController. First, the interface:

/* MyViewController.h */

@interface MyViewController : UIViewController<ABPeoplePickerNavigationControllerDelegate>
...
@end

Your controller might inherit from a descendant of UIViewController (like a table view controller or something like that) - that shouldn't change, the only thing that should change is adding the ABPeoplePickerNavigationControllerDelegate to the list of implemented protocols.

Now, to implement the functionality:

/* MyViewController.m */

@implementation MyViewController

...
- (void) whateverMethodIsDisplayingTheAddressBook
{
    ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc]init];    
    abPicker.peoplePickerDelegate = self; // This view controller is the delegate
    [self presentModalViewController:abPicker animated:YES];
    [abPicker release];
}

...

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

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
{   
    [super dismissModalViewControllerAnimated:YES];

    ...get stuff from the Address Book...   

    return NO;
}

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

@end
Matt
  • 678
  • 1
  • 6
  • 13
  • I delayed in responding because I'm trying to implement the concept you are showing. I understand the big picture but when I put to code what I believe you mean, I go from a clean compile to 10 errors. Then I tried to integrate AddressBookDelegate into MyprogAppDelegate only to come up to the wall that MyprogAppDelegate was derived from NSObject and the dismissModalViewControllerAnimated method must be derived from a UIViewController object. I'm going back to your structure again to see if I can flesh it out. I understand your "Don't do this" example that I was on the wrong track. – Ric Dec 03 '11 at 23:28
  • In your abouve struction I don't see where you duplicate the functionality of @interfact AddressBookDelegate : UIViewController because the ABPeoplePickerNavigationControllerDelegate protocol must derive from a UIViewController. May I prevail upon you to recode your example with a little more detail for me ? I am giving it the time, not being flippant. – Ric Dec 03 '11 at 23:50
  • After spending some more time looking at the documentation, I rewrote it. Biggest change is that you shouldn't be using the AppDelegate at all, but rather make whatever view controller that is spawning the address book the people picker delegate. – Matt Dec 05 '11 at 02:18
0

In the end I was not able to make any of the above suggestions perform as hoped for. I had to cut time and move on so I duplicated the code in each view. I will revisit this another time, as I am sure it can be done in a more object based way than I ended it doing it.

Ric
  • 796
  • 12
  • 28