IOS8 errors: ABPersonViewController not displaying properties and back button
The following code works correctly in iOS7, but not in iOS8 (the variable is recordID
set correctly):
CFErrorRef error = nil;
const ABAddressBookRef addressBook = (ABAddressBookCreateWithOptions (NULL, &error));
ABRecordRef contactRef = ABAddressBookGetPersonWithRecordID (addressBook, recordID);
ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
personViewController.addressBook = addressBook;
personViewController.displayedPerson = contactRef;
CFRelease(addressBook);
NSArray *displayedProperties = @[@(kABPersonFirstNameProperty),
@(kABPersonLastNameProperty),
@(kABPersonMiddleNameProperty),
@(kABPersonPrefixProperty),
@(kABPersonSuffixProperty),
@(kABPersonOrganizationProperty),
@(kABPersonJobTitleProperty),
@(kABPersonDepartmentProperty),
@(kABPersonEmailProperty),
@(kABPersonBirthdayProperty),
@(kABPersonKindProperty),
@(kABPersonAddressProperty),
@(kABPersonPhoneProperty),
@(kABPersonInstantMessageProperty),
@(kABPersonURLProperty),
@(kABPersonSocialProfileProperty),
@(kABPersonNoteProperty)];
personViewController.displayedProperties = displayedProperties;
personViewController.navigationItem.title = NSLocalizedString(@"CONTACT_DETAILS", nil);
personViewController.allowsActions = YES;
personViewController.allowsEditing = YES; // if NO, no back button is shown
personViewController.personViewDelegate = self;
personViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"ADDRESSES",nil) style:UIBarButtonItemStylePlain target:self action:@selector(personviewDoneButtonPressed:)];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:personViewController];
[self presentViewController:navigationController animated:YES completion:nil];
Errors in iOS8:
- If the parameter is
allowsEditing
set to a valueYES
, the contact is displayed, but only the name is displayed . The navigation bar displays a Back button (named Addresses) and to the right of the edit button. When the edit button is clicked, the contact is displayed with all fields blank except the name , and the edit button is displayed as a made button. If this button is pressed without any editing, all contact information is displayed . - If the parameter is
allowsEditing
set to a valueNO
, the back button is not displayed so that the screen can no longer remain.
Does anyone have a workaround?
UPDATE:
I realized that on the simulet sometimes only 1 sometimes , although always on my device >.
source to share
montuno (thanks again) who commented on my first answer got a hint from Apple tech support how to fix the first problem and now I understand the second problem too:
1) Only part of the displayed contact is displayed:
Apple stated that the following code is incorrect:
ABRecordRef contactRef = ABAddressBookGetPersonWithRecordID (addressBook, recordID);
ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
personViewController.addressBook = addressBook;
personViewController.displayedPerson = contactRef;
CFRelease(addressBook);
Here is addressBook
erroneously released after he was appointed ABPersonViewController
.
In my original code, I didn't have an operator CFRelease
. But then the static analyzer warned about "a potential leak of an object stored in the address book." After I inserted the release statement, the build went through without warning, so I assumed I personViewController
kept it addressBook
, which is apparently not the case, at least not with iOS8. I removed the release statement again, got a warning, but everything works fine.
2) Missing back button:
The docs ABPersonViewController
say "IMPORTANT Person view controllers must be used with a navigation controller to work properly."
So what I did is this:
I installed ABPersonViewController
assigned to its navigationItem.backBarButtonItem
a "Done" button and initialized a new one UINavigationController
with that personViewController
using initWithRootViewController:
. Then I introduced a new navigationController
modally.
A personViewController
back button appeared and when clicked, the view controller rendered the rejected navigation controller. This worked fine on iOS 8, but in iOS8 the back button was not displayed when allowsEditing
set to NO
.
But that doesn't seem to be how Apple wants to display personViewController
:
I think Apple assumes that it navigationController
already exists and represents the current view, so a new one is personViewController
simply pushed onto the stack navigationController
. In this case, it personViewController
does not rootViewController
navigationController
, but navigationController
automatically displays a return button (which is not executed for rootViewController
). If you implement this method, everything works fine for iOS8 as well.
source to share
UPDATE: This hack no longer works and is completely useless (see my new answer)
In case anyone has the same problem 1) above, here is a really dirty workaround until Apple fixes the bug (my bug reports are still open):
Since it is required to toggle the edit button twice after displaying the screen in some situations ABPersonViewController
, this is can be done programmatically:
Define a property for UINavigationController
that represents ABPersoViewController
:
@property (nonatomic, strong) UINavigationController * navigationControllerForPersonViewController;
After the navigation controller presents the face view controller, execute the selector to perform the toggle:
[self performSelector:@selector(toggleEditButton) withObject:nil afterDelay:0.7];
The delay is set so that the human view manager screen can be displayed with animation. The method is toggleEditButton
defined as:
- (void)toggleEditButton
{
UIBarButtonItem *editButton = self.navigationControllerForPersonViewController.topViewController.navigationItem.rightBarButtonItem;
id target = editButton.target;
SEL editAction = editButton.action;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[target performSelector:editAction withObject:editButton];
[target performSelector:editAction withObject:editButton];
#pragma clang diagnostic pop
}
#pragmas are needed to suppress compiler warnings for potential memory leaks.
This will display all of the selected Human View Manager information.
source to share