Как синхронизировать NSDocument с Mac OSX на iPad/iPhone с помощью iCloud

Я видел пример кода iCloud Document для iOS и использовал его для синхронизации udocument в iCloud и из него, и теперь я пытаюсь синхронизировать iCloud с nsdocument в приложении Mac OSX, в котором нет UIDocument.

Я пытался изменить UIDocument на NSDocument, но все методы синхронизации с icloud отличаются. Я не нашел ни одного примера кода или руководств, кроме документации из apple, что очень запутанно и плохо написано.

Например, приведенный ниже метод из UIDocument в iOS не существует в NSDocument в OS X:

//doc is an instance of subclassed UIDocument
[doc openWithCompletionHandler:nil];

Документация Apple предоставляет этот код для OS X:

- (void)checkIfCloudAvaliable {
    NSURL *ubiquityContainerURL = [[[NSFileManager defaultManager]
                                    URLForUbiquityContainerIdentifier:nil]
                                   URLByAppendingPathComponent:@"Documents"];
    if (ubiquityContainerURL == nil) {
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                              NSLocalizedString(@"iCloud does not appear to be configured.", @""),
                              NSLocalizedFailureReasonErrorKey, nil];
        NSError *error = [NSError errorWithDomain:@"Application" code:404
                                         userInfo:dict];
        [self presentError:error modalForWindow:[self windowForSheet] delegate:nil
        didPresentSelector:NULL contextInfo:NULL];
        return;
    }
    dest = [ubiquityContainerURL URLByAppendingPathComponent:
            [[self fileURL] lastPathComponent]];
}

- (void)moveToOrFromCloud {
    dispatch_queue_t globalQueue =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^(void) {
        NSFileManager *fileManager = [[NSFileManager alloc] init];
        NSError *error = nil;
        // Move the file.
        BOOL success = [fileManager setUbiquitous:YES itemAtURL:[self fileURL]
                                   destinationURL:dest error:&error];
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            if (! success) {
                [self presentError:error modalForWindow:[self windowForSheet]
                          delegate:nil didPresentSelector:NULL contextInfo:NULL];
            }
        });
    });
    [self setFileURL:dest];
    [self setFileModificationDate:nil];
}

Как я могу синхронизировать iOS и OS X (поскольку NSDocument не существует в iOS, а UIDocument не существует в OS X)? Кто-нибудь знает, где я могу найти образец для Mac OSX (синхронизация NSDocument)?


person Refael.S    schedule 27.01.2012    source источник
comment
Не все из нас находят документацию запутанной и плохо написанной.   -  person Abizern    schedule 28.01.2012
comment
Я использовал документацию, и это не сработало для меня.   -  person Refael.S    schedule 28.01.2012
comment
В качестве альтернативы - почему бы не показать часть кода, который вы пробовали, вместо того, чтобы искать что-то, что вы можете вырезать и вставить. Вы сделали это для iOS, так что у вас должно быть некоторое представление о потоке.   -  person Abizern    schedule 28.01.2012
comment
Вот, пожалуйста, я вставил код из документации, который у меня не сработал.   -  person Refael.S    schedule 29.01.2012


Ответы (3)


Мне удалось заставить его работать! Вот мой код из подкласса nsdocument в OS X :

Заголовочный файл:

#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>

@interface subclassedNSDocument : NSDocument

@property (strong) NSData *myData;

@end

Файл реализации:

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError 
{
    BOOL readSuccess = NO;
    if (data) 
    {
        readSuccess = YES;
        [self setMyData:data];
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:@"dataModified" 
                                                        object:self];

    return readSuccess;
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError 
{
    if (!myData && outError) {
        *outError = [NSError errorWithDomain:NSCocoaErrorDomain
                                        code:NSFileWriteUnknownError userInfo:nil];
    }
    return myData;
}

и в файле AppDelegate.m:

#define kFILENAME @"mydocument.dox"

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSURL *ubiq = [[NSFileManager defaultManager] 
                   URLForUbiquityContainerIdentifier:nil];
    if (ubiq) {
        NSLog(@"iCloud access at %@", ubiq);
        // TODO: Load document... 
        [self loadDocument];
    }
    else 
    {
        NSLog(@"No iCloud access");
    }

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(dataReloaded:) 
                                                 name:@"dataModified" object:nil];
}

- (void)update_iCloud
{
    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:kFILENAME];
    self.doc.myData = [NSKeyedArchiver archivedDataWithRootObject:[@"Your Data Array or any data", nil]];
    [self.doc saveToURL:ubiquitousPackage ofType:@"dox" forSaveOperation:NSSaveOperation error:nil];
}

- (void)loadData:(NSMetadataQuery *)query {

    if ([query resultCount] == 1) {

        NSMetadataItem *item = [query resultAtIndex:0];
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
        NSLog(@"url = %@",url);
        subclassedNSDocument *doc = [[subclassedNSDocument alloc] initWithContentsOfURL:url ofType:@"dox" error:nil];
        [doc setFileURL:url];
        self.doc = doc;
    } 
    else {

        NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
        NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:kFILENAME];

        dataUrls *doc = [[dataUrls alloc] init];
        [self.doc setFileURL:ubiquitousPackage];
        self.doc = doc;
        [self.doc saveToURL:ubiquitousPackage ofType:@"dox" forSaveOperation:NSSaveOperation error:nil];
    }

}

- (void)queryDidFinishGathering:(NSNotification *)notification {

    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];

    [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                    name:NSMetadataQueryDidFinishGatheringNotification
                                                  object:query];

    _query = nil;

    [self loadData:query];

}

- (void)loadDocument {

    NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
    _query = query;
    [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
    NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K == %@", NSMetadataItemFSNameKey, kFILENAME];
    [query setPredicate:pred];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];

    [query startQuery];

}

- (void)dataReloaded:(NSNotification *)notification 
{
    self.doc = notification.object;

    NSArray *arrFromCloud = [NSKeyedUnarchiver unarchiveObjectWithData:self.doc.myData];

    //Update you UI with new data
}

Единственное, что у меня не работает, это то, что если я изменяю данные документа на iPad, приложение Mac не вызывает метод readFromData для обновления из iCloud, кто-нибудь знает, что мне не хватает?

В iOS эквивалентный метод loadFromContents вызывается автоматически при каждом изменении UIDocument в iCloud. В OS X readFromData вызывается один раз при загрузке, но больше никогда не вызывается.

Надеюсь, мой код может помочь, для меня он работает в одну сторону с Mac на iPad.

person Refael.S    schedule 29.01.2012
comment
@user1173374 user1173374 Вы не должны задавать больше вопросов в ответе на StackOverflow. Вместо этого начните новый вопрос. В своем новом вопросе вы можете ссылаться на этот ответ для справки. - person Sam Spencer; 02.01.2013
comment
@Olof Я разместил вопрос об обновлении с iPad на Mac здесь: stackoverflow.com/questions/20984512/ - person Refael.S; 08.01.2014

Я думаю, что NSMetadataQueryDidUpdateNotification - это то, что вы ищете для обнаружения обновления документа.

Это можно использовать так же, как NSMetadataQueryDidFinishGatheringNotification.

person user1263865    schedule 12.03.2012

Если вы имеете дело с файлами в дополнение к основным данным. Вот лучший учебник

http://samvermette.com/312

person ThE uSeFuL    schedule 05.03.2013