Как использовать iCloud для хранения и синхронизации файлов
У меня уже есть приложение для iPhone, которое хранит данные в файле в папке локальных документов. Теперь я узнал о технологиях iCloud, и мой первый вопрос был: есть ли способ использовать iCloud в качестве каталога, когда иногда я проверяю новые версии?
Я имею в виду: могу ли я избежать использования UIDocument, координаторов файлов и докладчиков файлов? Я просто хочу знать, можно ли рассматривать iCloud как специальную папку и использовать NSFileManager только для нажатия и извлечения файлов.
последнее примечание: Я не используйте Core Data или любую базу данных, у меня есть только файл данных.
Edit:
Я уже прочитал официальную документацию Apple iCloud, поэтому не связывайте меня с ними. Мне нужны только примеры кода.
5 ответов
Я знаю, как вы себя чувствуете, iCloud немного пугает. Тем не менее, я думаю, что нет никакого способа обойти UIDocument, файловые координаторы и т. д. и просто использовать iCloud как простую папку.
Если вы ищете простой для понимания пример кода, пожалуйста, посмотрите на этот пост:
Я включил полный пример кода, который охватывает голые минимумы iCloud и в значительной степени использует его как каталог. Возможно, это делает это менее сложно для вас использовать UIDocument, файловые координаторы и т. д.
но, как и вы, я хотел бы, чтобы был более простой и совместимый способ с идеей старой доброй документальной папки. Однако, поскольку это iCloud, и iCloud делает еще несколько вещей (например, синхронизирует все на разных устройствах, постоянно обновляется до облака и т. д.), не будет никакого пути вокруг UIDocument etc.
что "работает" для меня-это просто:
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return NO;
}
NSError *theError = nil;
[fm setUbiquitous:true itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];
Apple говорит, чтобы вызвать не-UI поток. Наличие файлов "перемещено". Вы можете запросить их через NSMetaDataQuery
такой:
self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K like '*.db'", NSMetadataItemFSNameKey];
[self.query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
[self.query startQuery];
- (void)queryDidFinishGathering:(NSNotification *)notification {
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[self loadData:query];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
self.query = nil;
}
пример перечисления через результаты запроса:
- (void)loadData:(NSMetadataQuery *)query {
[self.backups removeAllObjects];
for (NSMetadataItem *item in [query results]) {
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
[self.backups addObject:url.lastPathComponent];
}
[_table reloadData];
[self.loadingBackupIndicator stopAnimating];
self.loadingIndicatorLabel.text = [NSString stringWithFormat: @"%d backups found", [self.backups count]];
}
и начать "загрузку" конкретного файла:
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return NO;
}
NSError *theError = nil;
bool started = [fm startDownloadingUbiquitousItemAtURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];
NSLog(@"started download for %@ %d", backupName, started);
if (theError != nil) {
NSLog(@"iCloud error: %@", [theError localizedDescription]);
}
с проверками для файла "загружается":
- (BOOL)downloadFileIfNotAvailable {
NSNumber *isIniCloud = nil;
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *file = [[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:self.backupName];
if ([file getResourceValue:&isIniCloud forKey:NSURLIsUbiquitousItemKey error:nil]) {
// If the item is in iCloud, see if it is downloaded.
if ([isIniCloud boolValue]) {
NSNumber* isDownloaded = nil;
if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) {
if ([isDownloaded boolValue]) {
[self.loadingBackupIndicator stopAnimating];
self.loadingIndicatorLabel.text = @"Downloaded";
....
[[NSFileManager defaultManager] copyItemAtPath:[file path] toPath:restorePath error:&theError ];
....
return YES;
}
self.loadingCheckTimer = [NSTimer timerWithTimeInterval:3.0f target:self selector:@selector(downloadFileIfNotAvailable) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:self.loadingCheckTimer forMode:NSDefaultRunLoopMode];
return NO;
}
}
}
return YES;
}
Я не ожидал, что код будет таким длинным и извините за предоставление здесь очень сырые фрагменты. Никакое намерение сказать выше не может быть качеством производства кода, просто разделяя концепцию.
Я еще не отправил это внутри моего приложения в Apple, поэтому не могу сказать, что это будет "одобрено" в app store (если они найдут или позаботятся...)
вы можете загружать отдельные файлы в iCloud с помощью NSFileManager. Я опубликовал полное прохождение игры о том, как это сделать в моем блоге, но вот соответствующий код NSFileManager:
NSURL *destinationURL = [self.ubiquitousURL URLByAppendingPathComponent:@"Documents/image.jpg"]
[[NSFileManager defaultManager] setUbiquitous:YES
itemAtURL:sourceURL
destinationURL:destinationURL
error:&error]
на самом деле нет способа обойти использование UIDocument. Я попытался сделать это в одном из моих первых применений iCloud, но это оказалось катастрофой без UIDocument. Использование UIDocument сначала кажется большой дополнительной работой, но это не так.
вы можете легко подкласс UIDocument в течение часа и заставить его работать с любым типом файла (просто установите content
свойство как NSData). Он также предоставляет многочисленные преимущества по сравнению со стандартной файловой системой:
- изменить отслеживание
- разрешение конфликтов файлов
- государственный документ
- расширенные функции сохранения / открытия / закрытия
честно говоря, тратить всего час или два на чтение документации Apple, а затем использовать его стоит времени и мозговой энергии. Хорошая стартовая статья о хранилище документов iCloud можно найти в документация разработчика Apple.
я написал подкласс UIDocument, который будет работать с любым типом файла (в частности, NSData). Вы можете просмотреть, загрузить и изменить код подкласса UIDocument на GitHub.
создать документ:
// Initialize a document with a valid file path
iCloudDocument *document = [[iCloudDocument alloc] initWithFileURL:fileURL];
// Set the content of the document
document.contents = content;
// Increment the change count
[document updateChangeCount:UIDocumentChangeDone];
сохранить существующий документ:
// Save and close the document
[document closeWithCompletionHandler:nil];
сохранить новый документ:
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:nil];
вы также можете синхронизировать все файлы, хранящиеся в iCloud, с помощью NSMetadataQuery. Apple предоставляет очень хороший пример использования запроса NSMetadata для синхронизации файлов приложений. Также убедитесь, что регистрация в iCloud перед выполнением этих операций (подсказка: используйте ubiquityIdentityToken
метод в NSFileManager).
вы также можете рассмотреть возможность использования библиотеки с открытым исходным кодом, такой как синхронизация документов iCloud. Проект синхронизации документов iCloud упрощает хранение и синхронизацию файлов приложений:
интеграция iCloud в проекты документов iOS с помощью методов однострочного кода. Синхронизация, загрузка, управление и удаление документов из iCloud быстро и легко. Помогает чтобы iCloud "просто работал"для разработчиков.
почти в каждом методе синхронизации документов iCloud все, что вам нужно сделать, это передать данные файла в качестве параметра, а затем он обрабатывает остальные (сохранение, синхронизация и т. д.).
отказ от ответственности: я участвую в разработке проекта с открытым исходным кодом iCloud Document Sync. Однако я считаю, что этот проект будет для вас выгоден, и имеет отношение к этому вопросу. Это не повышение или реклама.
используйте этот код:
+ (NSString *)Pathsave {
NSString *os5 = @"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedAscending) {
// Lower than 4
return path;
} else if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedDescending) {
// 5.0.1 and above
return path;
} else {
// iOS 5
path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
return path;
}
return nil;
}