如何观察 ABPerson 的 ABPersonView 变化
How to observe ABPersonView changes for ABPerson
我知道 ABPersonView 不是 KVO 投诉。我的问题是,尽管每次我访问 属性 时都声明了 ABPersonView 的 属性,但我得到了不同的对象。我是在做错什么,还是每次 ABPersonView 发生变化时我都必须用新的 ABPerson 对象更新模型?使用 El Capitan GM。
ABPersonView:
@property (readwrite, retain) ABPerson *person;
// An ABPerson record for display.
// Raises if person originates from ABAddressBook's +sharedAddressBook.
// Person must be exist in an ABAddressBook created and manipulated on the main thread only.
// When person is nil, displays an empty selection state.
代码:
#import "AppDelegate.h"
@import AddressBook;
static void * ABPersonVCContext = &ABPersonVCContext;
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (strong) ABPerson *person;
@property (strong) ABPersonView *personView;
@property (strong) ABAddressBook *book;
@property (assign, getter=isEditing) BOOL editing;
@property NSTimer *timer;
@end
@implementation AppDelegate
- (instancetype)init {
self = [super init];
if (self) {
_book = [[ABAddressBook alloc] init];
NSString *vCardRepresentation = @"BEGIN:VCARD\r\nVERSION:3.0\r\nN:AA;BB;;;\r\nFN:\r\nEND:VCARD\r\n";
NSData *vCardData = [vCardRepresentation dataUsingEncoding:NSUTF8StringEncoding];
_person = [[ABPerson alloc] initWithVCardRepresentation:vCardData];
[_book addRecord:_person];
[self addObserver:self forKeyPath:@"editing"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:ABPersonVCContext];
#ifdef DEBUG
NSLog(@"%s %d %s", __FILE__, __LINE__, __PRETTY_FUNCTION__);
NSLog(@"%@",_person);
#endif
}
return self;
}
- (void)awakeFromNib
{
self.personView = [[ABPersonView alloc] initWithFrame:self.window.contentView.frame];
self.personView.person = self.person;
[self.window.contentView addSubview:self.personView];
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(reverseEditing) userInfo:NULL repeats:YES];
[self.timer fire];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == ABPersonVCContext) {
if ([keyPath isEqualTo:@"editing"]) {
#ifdef DEBUG
NSLog(@"%s %d %s", __FILE__, __LINE__, __PRETTY_FUNCTION__);
NSLog(@"%@",self.personView.person);
#endif
}
} else {
@try {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
@catch (NSException *exception) {
;
}
@finally {
;
}
}
}
- (void)reverseEditing
{
self.editing = !self.editing;
}
@end
编辑:
新对象来自不同的 addressBook 实例:
(lldb) po [newPerson addressBook]
<ABAddressBook: 0x6080000d50e0>
(lldb) po self.book
<ABAddressBook: 0x6080000c4130>
(lldb) po [self.person addressBook]
<ABAddressBook: 0x6080000c4130>
编辑2:
即使注册通知也无济于事,因为正在修改不同的对象。
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(changeOccured:) name:kABDatabaseChangedNotification object:nil];
[nc addObserver:self selector:@selector(changeOccured:) name:kABDatabaseChangedExternallyNotification object:nil];
不幸的是,每次调用 personView 的 person 属性 都会触发 ABPersonViewAPIAdapter,它将 CNContact 转换为 ABPerson。因此,如果不想在 El Capitan 上使用 CNContact,他必须将编辑后的 ABPerson 传播回模型对象。
可以尝试下面的代码(希望这会为某人节省一些时间)
NSLog(@"%@",[self.personView performSelector:@selector(addressBook) withObject:nil]);
NSLog(@"%@",[self.personView performSelector:@selector(_APIAdapter) withObject:nil]);
NSLog(@"%@",[self.personView performSelector:@selector(_contact) withObject:nil]);
我知道 ABPersonView 不是 KVO 投诉。我的问题是,尽管每次我访问 属性 时都声明了 ABPersonView 的 属性,但我得到了不同的对象。我是在做错什么,还是每次 ABPersonView 发生变化时我都必须用新的 ABPerson 对象更新模型?使用 El Capitan GM。
ABPersonView:
@property (readwrite, retain) ABPerson *person;
// An ABPerson record for display.
// Raises if person originates from ABAddressBook's +sharedAddressBook.
// Person must be exist in an ABAddressBook created and manipulated on the main thread only.
// When person is nil, displays an empty selection state.
代码:
#import "AppDelegate.h"
@import AddressBook;
static void * ABPersonVCContext = &ABPersonVCContext;
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (strong) ABPerson *person;
@property (strong) ABPersonView *personView;
@property (strong) ABAddressBook *book;
@property (assign, getter=isEditing) BOOL editing;
@property NSTimer *timer;
@end
@implementation AppDelegate
- (instancetype)init {
self = [super init];
if (self) {
_book = [[ABAddressBook alloc] init];
NSString *vCardRepresentation = @"BEGIN:VCARD\r\nVERSION:3.0\r\nN:AA;BB;;;\r\nFN:\r\nEND:VCARD\r\n";
NSData *vCardData = [vCardRepresentation dataUsingEncoding:NSUTF8StringEncoding];
_person = [[ABPerson alloc] initWithVCardRepresentation:vCardData];
[_book addRecord:_person];
[self addObserver:self forKeyPath:@"editing"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:ABPersonVCContext];
#ifdef DEBUG
NSLog(@"%s %d %s", __FILE__, __LINE__, __PRETTY_FUNCTION__);
NSLog(@"%@",_person);
#endif
}
return self;
}
- (void)awakeFromNib
{
self.personView = [[ABPersonView alloc] initWithFrame:self.window.contentView.frame];
self.personView.person = self.person;
[self.window.contentView addSubview:self.personView];
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(reverseEditing) userInfo:NULL repeats:YES];
[self.timer fire];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == ABPersonVCContext) {
if ([keyPath isEqualTo:@"editing"]) {
#ifdef DEBUG
NSLog(@"%s %d %s", __FILE__, __LINE__, __PRETTY_FUNCTION__);
NSLog(@"%@",self.personView.person);
#endif
}
} else {
@try {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
@catch (NSException *exception) {
;
}
@finally {
;
}
}
}
- (void)reverseEditing
{
self.editing = !self.editing;
}
@end
编辑: 新对象来自不同的 addressBook 实例:
(lldb) po [newPerson addressBook]
<ABAddressBook: 0x6080000d50e0>
(lldb) po self.book
<ABAddressBook: 0x6080000c4130>
(lldb) po [self.person addressBook]
<ABAddressBook: 0x6080000c4130>
编辑2: 即使注册通知也无济于事,因为正在修改不同的对象。
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(changeOccured:) name:kABDatabaseChangedNotification object:nil];
[nc addObserver:self selector:@selector(changeOccured:) name:kABDatabaseChangedExternallyNotification object:nil];
不幸的是,每次调用 personView 的 person 属性 都会触发 ABPersonViewAPIAdapter,它将 CNContact 转换为 ABPerson。因此,如果不想在 El Capitan 上使用 CNContact,他必须将编辑后的 ABPerson 传播回模型对象。
可以尝试下面的代码(希望这会为某人节省一些时间)
NSLog(@"%@",[self.personView performSelector:@selector(addressBook) withObject:nil]);
NSLog(@"%@",[self.personView performSelector:@selector(_APIAdapter) withObject:nil]);
NSLog(@"%@",[self.personView performSelector:@selector(_contact) withObject:nil]);