以下代码在iOS7中正常工作,但在iOS8中不正常(变量recordID
设置正确):
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];
iOS8:中的错误
- 当
allowsEditing
设置为YES
时,会显示联系人,但仅显示名称。导航栏左侧显示后退按钮(名为"Addresses"),右侧显示编辑按钮。当按下编辑按钮,联系人将显示所有字段除名称外为空,编辑按钮显示为完成按钮如果按下此完成按钮而之前未进行任何编辑,将显示有关联系人的所有信息 - 当
allowsEditing
设置为NO
时,不会显示后退按钮,因此屏幕不能再离开了
有人能解决问题吗?
更新:
我现在意识到,问题1只有有时发生在模拟器上,尽管在我的设备上总是。
montuno(再次感谢),他评论了我的第一个答案,从苹果技术支持那里得到了如何解决第一个问题的提示,我现在也理解了第二个问题:
1) 仅显示部分联系人:
苹果声称以下代码是错误的:
ABRecordRef contactRef = ABAddressBookGetPersonWithRecordID (addressBook, recordID);
ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
personViewController.addressBook = addressBook;
personViewController.displayedPerson = contactRef;
CFRelease(addressBook);
这里,addressBook
在被分配给ABPersonViewController
之后被错误地释放。
在我的原始代码中,我没有CFRelease
语句。但随后静态分析器警告"addressBook中存储的对象可能泄漏"。在我插入发布语句后,构建成功,没有任何警告,所以我假设personViewController
保留了addressBook
,但显然不是这样,至少iOS8不是这样。我现在又删除了发布声明,收到了警告,但一切都很好。
2) 缺少后退按钮:ABPersonViewController
的文档中说"重要人物视图控制器必须与导航控制器一起使用才能正常工作"
所以我做了以下事情:
我设置了一个ABPersonViewController
,分配给它的navigationItem.backBarButtonItem
一个"Done"按钮,并使用initWithRootViewController:
用这个personViewController
初始化了一个新的UINavigationController
。然后我以模式呈现了新的navigationController
。
显示带有后退按钮的personViewController
,当按下时,呈现视图控制器解除模式呈现的导航控制器
这在iOS上运行良好<8,但在iOS8中,当allowsEditing
设置为NO
时,不显示后退按钮。
但这显然不是苹果想要的personViewController
:
我认为Apple假设navigationController
已经存在,并呈现当前视图,因此新的personViewController
只是被推送到navigationController
的堆栈上。在这种情况下,personViewController
不是navigationController
的rootViewController
,并且navigationController
自动显示后退按钮(这对于rootViewController
没有完成)。如果以这种方式实现,iOS8也可以正常工作。
更新:此破解不再有效,完全无用(请参阅我的新答案)
如果有人遇到了上述1)相同的问题,在苹果修复错误之前,这里有一个非常糟糕的解决方法(我的错误报告仍然打开):
由于在某些情况下需要在显示ABPersonViewController
屏幕后切换编辑按钮两次,因此可以通过编程方式执行此操作:
为显示ABPersoViewController
:的UINavigationController
定义一个属性
@property (nonatomic, strong) UINavigationController * navigationControllerForPersonViewController;
导航控制器显示人物视图控制器后,执行选择器进行切换:
[self performSelector:@selector(toggleEditButton) withObject:nil afterDelay:0.7];
设置延迟,以便人员视图控制器屏幕可以显示动画。方法toggleEditButton
定义为:
- (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
}
需要#pragma来抑制编译器对潜在内存泄漏的警告
结果是实际显示了人物视图控制器的所有选择信息。