NSDiptributedNotifications를 사용하여 프로세스간에 핵심 데이터 저장소를 어떻게 공유합니까?
문제
배경
나는 이미 기본 사항에 대한 질문을 게시했습니다 프로세스간에 핵심 데이터 저장소 공유.
주어진 권장 사항을 구현하려고 노력하고 있으며 문제가 발생합니다.
내 목표
Helper App과 UI의 두 가지 프로세스가 있습니다. 둘 다 단일 데이터 저장소를 공유합니다. Helper 앱이 새로운 데이터를 매장에 저장했을 때 UI가 NSmanagedObjectContext를 업데이트하기를 원합니다.
현재 프로그램 흐름
도우미 앱 프로세스는 데이터를 매장에 씁니다.
헬퍼 앱에서는 nsmanagedObjectContextDidSavenotification 알림을 듣습니다.
컨텍스트가 저장되면 URI 표현 및 NSARCHIVER를 사용하여 삽입, 삭제 및 업데이트 된 객체를 인코딩합니다.
이 인코딩 된 사전을 userInfo로 NSDiptributedNotificationCenter에 NSNotification을 보냅니다.
UI 프로세스는 저장 알림을 듣고 있습니다. 알림을 받으면 nsunarchiver를 사용하여 userinfo를 구제하지 않습니다.
주어진 URI에서 업데이트 된/삽입/삭제 된 객체를 모두 찾아 NsmanagedObjects로 대체합니다.
업데이트 된/삽입/삭제 된 객체와 함께 NSNotification을 구성합니다.
나는 mergechangesfromcontextDidsavenotification을 호출합니다. UI 프로세스의 관리 된 객체 컨텍스트에서 이전 단계에서 구성된 nsnotification을 통과합니다.
문제
삽입 된 객체는 UI 관리 객체 컨텍스트에 대해 결함이 있으며 UI에 나타납니다. 문제는 업데이트 된 객체와 함께 제공됩니다. 그들은 단지 업데이트하지 않습니다.
내가 시도한 것
가장 분명한 것은 헬퍼 앱 프로세스에서 UI 프로세스로 저장 알림을 전달하는 것입니다. 쉽지? 음 ... 아니. userinfo 사전이 올바른 형식이 아니기 때문에 분산 알림은이를 수행 할 수 없습니다. 그것이 내가 모든 nsarchiving 일을하고있는 이유입니다.
나는 nsmanagedObjects에서 업데이트 될 nmanagedObjects에서 refreshObject : mergechanges를 호출하려고 시도했지만 이것은 효과가없는 것 같습니다.
메인 스레드와 현재 스레드에서 MergechangesfromcontextDidsavenotification : 선택기를 수행하려고 시도했습니다. 결과에 영향을 미치지 않는 것 같습니다.
나는 mergechangesfromcontextDidsavenotification을 사용해 보았습니다. 스레드 사이에, 물론 훨씬 더 단순하고 완벽하게 작동했습니다. 그러나 프로세스간에 동일한 기능이 필요합니다.
대안?
내가 여기서 뭔가를 놓치고 있습니까? 나는 필요한 것보다 훨씬 더 복잡해지는 느낌을 지속적으로 이해하고 있지만 문서를 여러 번 읽고 며칠을 며칠을 보낸 후에는 MOC를 새로 고치는 다른 방법을 볼 수 없습니다. UI.
더 우아한 방법이 있습니까? 아니면 내 코드 어딘가에 어리석은 실수를하고 있습니까?
코드
나는 그것을 가능한 한 읽을 수있게 만들려고 노력했지만 여전히 엉망입니다. 죄송합니다.
도우미 앱 코드
-(void)workerThreadObjectContextDidSave:(NSNotification *)saveNotification {
NSMutableDictionary *savedObjectsEncodedURIs = [NSMutableDictionary dictionary];
NSArray *savedObjectKeys = [[saveNotification userInfo] allKeys];
for(NSString *thisSavedObjectKey in savedObjectKeys) {
// This is the set of updated/inserted/deleted NSManagedObjects.
NSSet *thisSavedObjectSet = [[saveNotification userInfo] objectForKey:thisSavedObjectKey];
NSMutableSet *thisSavedObjectSetEncoded = [NSMutableSet set];
for(id thisSavedObject in [thisSavedObjectSet allObjects]) {
// Construct a set of URIs that will be encoded as NSData
NSURL *thisSavedObjectURI = [[(NSManagedObject *)thisSavedObject objectID] URIRepresentation];
[thisSavedObjectSetEncoded addObject:thisSavedObjectURI];
}
// Archive the set of URIs.
[savedObjectsEncodedURIs setObject:[NSArchiver archivedDataWithRootObject:thisSavedObjectSetEncoded] forKey:thisSavedObjectKey];
}
if ([[savedObjectsEncodedURIs allValues] count] > 0) {
// Tell UI process there are new objects that need merging into it's MOC
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.synapticmishap.lapsus.save" object:@"HelperApp" userInfo:(NSDictionary *)savedObjectsEncodedURIs];
}
}
UI 코드
-(void)mergeSavesIntoMOC:(NSNotification *)notification {
NSDictionary *objectsToRefresh = [notification userInfo];
NSMutableDictionary *notificationUserInfo = [NSMutableDictionary dictionary];
NSArray *savedObjectKeys = [[notification userInfo] allKeys];
for(NSString *thisSavedObjectKey in savedObjectKeys) {
// Iterate through all the URIs in the decoded set. For each URI, get the NSManagedObject and add it to a set.
NSSet *thisSavedObjectSetDecoded = [NSUnarchiver unarchiveObjectWithData:[[notification userInfo] objectForKey:thisSavedObjectKey]];
NSMutableSet *savedManagedObjectSet = [NSMutableSet set];
for(NSURL *thisSavedObjectURI in thisSavedObjectSetDecoded) {
NSManagedObject *thisSavedManagedObject = [managedObjectContext objectWithID:[persistentStoreCoordinator managedObjectIDForURIRepresentation:thisSavedObjectURI]];
[savedManagedObjectSet addObject:thisSavedManagedObject];
// If the object is to be updated, refresh the object and merge in changes.
// This doesn't work!
if ([thisSavedObjectKey isEqualToString:NSUpdatedObjectsKey]) {
[managedObjectContext refreshObject:thisSavedManagedObject mergeChanges:YES];
[managedObjectContext save:nil];
}
}
[notificationUserInfo setObject:savedManagedObjectSet forKey:thisSavedObjectKey];
}
// Build a notification suitable for merging changes into MOC.
NSNotification *saveNotification = [NSNotification notificationWithName:@"" object:nil userInfo:(NSDictionary *)notificationUserInfo];
[managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:saveNotification
waitUntilDone:YES];
}
해결책
당신은 - (void) refreshObject를 찾고 있습니다 : (nsmanagedObject *) 객체 합병 : (bool) 플래그 나는 믿습니다.
이렇게하면 영구 저장소의 정보가 포함 된 객체를 새로 고치고 원하는 경우 변경 사항을 병합합니다.
다른 팁
나는 방법을 사용했다
http://www.mlsite.net/blog/?p=518
그러면 모든 객체가 올바르게 결함이 있지만 결함이 캐시에 가져 오므로 여전히 업데이트되지 않습니다.
나는 [moc stalenessinterval = 0]를해야했다.
그리고 그것은 마침내 관계와 함께 일했습니다.
나는 Mike의 제안과 함께 가서 변경 사항을 위해 상점 파일을 보았습니다.
가장 효율적이지는 않지만 성공을 거두었습니다. - [NSManagedObjectContext reset]
상점이 변경 될 때 두 번째 프로세스에서. 내 경우, 코드는 상당히 선형입니다. 재설정 후 일부 데이터에 대한 페치 요청을 실행하는 것입니다. 이것이 바인딩과 복잡한 UI로 어떻게 작동하는지 모르겠지만 자동으로 처리되지 않으면 물건을 수동으로 업데이트하기 위해 알림을 게시 할 수 있습니다.
나는 내가 작업 한 iPhone 앱과 똑같은 문제를 가졌다. 필자의 경우 솔루션은 컨텍스트의 Stalenessinterval을 적절한 무한대 (예 : 0.5 초)로 설정하는 것이 포함되었습니다.
이것은 샌드 박스 앱을 제외하고는 작동합니다. 사용자 정보 표시로 알림을 보낼 수 없습니다. 대신 XPC와 같은 다른 IPC를 고려하거나 DO를 고려하십시오.
참고로, NSDURTURIBEDNOTIFICECENTER를 사용하는 것이 시스템이 바쁘다면 항상 100%는 아닙니다.
관리되는 객체 컨텍스트의 Stalenessinterval 설정이 작동합니다. 내 사례에는 프로세스 대신 여러 스레드가 포함됩니다.