Обновленный ответ для повторной синхронизации ваших устройств Месяцы возни заставили меня выяснить, какова (я полагаю) корневая проблема.Проблема заключалась в том, что устройства перестали общаться друг с другом после того, как они перестали синхронизироваться.Я не могу точно сказать, чем это вызвано, но я подозреваю, что журнал транзакций поврежден или (что более вероятно) контейнер самого журнала воссоздан.Это было бы похоже на то, как устройство A отправляет изменения в контейнер A и устройство B, делая то же самое, а не как отправляет сообщения в контейнер C, где они могут читать / записывать в журналы.
Теперь, когда мы знаем проблему, этовопрос создания решения.Дальнейшее возрождение привело меня к следующему.У меня есть метод с именем resetiCloudSync:(BOOL)isSource
, который является измененной версией метода, описанного выше в моем первоначальном вопросе.
- (void)resetiCloudSync:(BOOL)isSource {
NSLog(@"reset sync source %d", isSource);
NSManagedObjectContext *moc = self.managedObjectContext;
if (isSource) {
// remove data from app's cloud account, then repopulate with copy of existing data;
// find your log transaction container;
NSURL *cloudURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSString *coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:@"store"];
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
NSError *error = nil;
// remove the old log transaction container and it's logs;
[[NSFileManager defaultManager] removeItemAtURL:cloudURL error:&error];
// rebuild the container to insert the "new" data into;
if ([[NSFileManager defaultManager] createFileAtPath:coreDataCloudContent contents:nil attributes:nil]) {
// this will differ for everyone else. here i set up an array that stores the core data objects that are to-many relationships;
NSArray *keyArray = [NSArray arrayWithObjects:@"addedFields", @"mileages", @"parts", @"repairEvents", nil];
// create a request to temporarily store the objects you need to replicate;
// my heirarchy starts with vehicles as parent entities with many attributes and relationships (both to-one and to-many);
// as this format is a mix of just about everything, it works great for example purposes;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Vehicle" inManagedObjectContext:moc];
[request setEntity:entity];
NSError *error = nil;
NSArray *vehicles = [moc executeFetchRequest:request error:&error];
for (NSManagedObject *object in vehicles) {
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:object.entity.name inManagedObjectContext:moc];
// check regular values;
for (NSString *key in object.entity.attributesByName.allKeys) {
[newObject setValue:[object valueForKey:key] forKey:key];
}
// check relationships;
NSMutableSet *relSet = [[NSMutableSet alloc] init];
for (NSString *key in object.entity.relationshipsByName.allKeys) {
[relSet removeAllObjects];
// check to see relationship exists;
if ([object valueForKey:key] != nil) {
// check to see if relationship is to-many;
if ([keyArray containsObject:key]) {
for (NSManagedObject *toManyObject in [object valueForKey:key]) {
[relSet addObject:toManyObject];
}
} else {
[relSet addObject:[object valueForKey:key]];
}
// cycle through objects;
for (NSManagedObject *subObject in relSet) {
NSManagedObject *newSubObject = [NSEntityDescription insertNewObjectForEntityForName:subObject.entity.name inManagedObjectContext:moc];
// check sub values;
for (NSString *subKey in subObject.entity.attributesByName.allKeys) {
NSLog(@"subkey %@", subKey);
[newSubObject setValue:[subObject valueForKey:subKey] forKey:subKey];
}
// check sub relationships;
for (NSString *subRel in subObject.entity.relationshipsByName.allKeys) {
NSLog(@"sub relationship %@", subRel);
// set up any additional checks if necessary;
[newSubObject setValue:newObject forKey:subRel];
}
}
}
}
[moc deleteObject:object];
}
[self resetStore];
}
} else {
// here we remove all data from the current device to populate with data pushed to cloud from other device;
for (NSManagedObject *object in moc.registeredObjects) {
[moc deleteObject:object];
}
}
[[[UIAlertView alloc] initWithTitle:@"Sync has been reset" message:nil delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil] show];
}
В этом коде у меня есть два различных пути.Один из них для устройств, которые не синхронизированы и должны иметь данные, импортированные из исходного устройства.Все, что делает этот путь, - это очищает память, чтобы подготовить ее для данных, которые должны быть в нем.
Другой (isSource = YES
) путь выполняет ряд задач.Как правило, он удаляет поврежденный контейнер.Затем он создает новый контейнер (для журналов, чтобы иметь место для проживания).Наконец, он просматривает родительские объекты и копирует их.То, что это делает, это повторно заполняет контейнер журнала транзакций информацией, которая должна быть там.Затем вам нужно удалить исходные объекты, чтобы у вас не было дубликатов.Наконец, сбросьте постоянное хранилище, чтобы «обновить» основные данные приложения и обновить все представления, и fetchedResultsControllers
.
Я могу засвидетельствовать, что это прекрасно работает.Я удалил данные с устройств (isSource = NO
), которые не общались с основным устройством (где хранятся данные) в течение нескольких месяцев.Затем я отправил данные с основного устройства и восхитительно наблюдал, как ВСЕ мои данные появились в течение нескольких секунд.
Опять же, пожалуйста, не стесняйтесь ссылаться и делиться этим со всеми, у кого были проблемы с синхронизацией с iCloud.
Ответ на оригинальный вопрос, который больше не затрагивается после выхода iOS 5.1, который исправил сбой после удаления хранилища iCloud вашего приложения в настройках
Через много-много часовизо всех сил пытаясь разобраться с этим, я попытался создать новый идентификатор приложения, обновил связанный профиль приложения, изменил поля контейнера iCloud, чтобы соответствовать новому профилю, и все снова работает.Я до сих пор не представляю, почему это произошло, но похоже, что хранилище iCloud, связанное с этим идентификатором приложения, повреждено?
Итак, суть в том, что если это случится с кем-то еще, следуйте этим шагам, и вы должны быть хороши
- Создайте новый идентификатор приложения на портале обеспечения.
- Найдите профиль обеспечения, связанный с приложением.Нажмите Edit-> Modify, затем измените ID приложения на тот, который вы только что создали.
- Отправьте изменение, затем замените существующий профиль в XCode на тот, который вы только что создали.
- Изменить всеэкземпляры
<bundleIdentifier>
для соответствия новому идентификатору приложения (это будет на главной странице вашего приложения, разрешениях для контейнеров iCloud и хранилища ключей-значений iCloud, а также в вашем файле AppDelegate, где вы создаете постоянное хранилище, как в моемкод выше). - Перезапустите Xcode, так как вы изменили информацию о профилях обеспечения (он будет жаловаться иначе и откажется запускаться на устройстве).
- Убедитесь, что новый профиль находится на устройствах, которые вы хотитеустановить приложение, затем собрать и запустить.На этом этапе все должно работать нормально.