简体   繁体   English

如何使用iCloud将Mac OS中的NSDocument与iPad / iPhone同步

[英]How to Sync an NSDocument from Mac osx to iPad/iPhone with iCloud

I have seen iCloud Document sample code for iOS and I used it to sync a to and from iCloud and now I am trying to sync iCloud with an on a Mac OSX app which doesn't have UIDocument . 我见过的iCloud文件示例代码为iOS和我用它来同步 ,并从iCloud中,现在我想用一个同步的iCloud 上没有一台Mac OSX应用UIDocument

I tried to change UIDocument to NSDocument but all the methods of syncing with are different. 我试图将UIDocument更改为NSDocument但所有与同步的方法都不同。 I haven't found any sample code or tutorials except for the documentation from which is very confusing and not well written. 我没有找到任何示例代码或教程,除了的文档,这是非常令人困惑和写得不好。

For example, the method below, from UIDocument on iOS does not exist in NSDocument on OS X: 例如,下面的方法,来自iOS上的UIDocument在OS X上的NSDocument中不存在:

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

The Apple Documentation provides this code for OS X: 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];
}

How can I sync between iOS and OS X (because NSDocument does not exists on iOS, and UIDocument does not exist on OS X)? 如何在iOS和OS X之间进行同步(因为iOS上不存在NSDocument ,OS X上不存在UIDocument )? Does anyone know where I can find a sample for Mac OSX ( NSDocument syncing)? 有谁知道我在哪里可以找到Mac OSX的样本( NSDocument同步)?

I managed to get it working! 我设法让它工作! Here's my code from the subclassed file on OS X: 这是我在OS X上的子类文件中的代码:

Header file: 头文件:

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

@interface subclassedNSDocument : NSDocument

@property (strong) NSData *myData;

@end

Implementation file: 实施文件:

- (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;
}

and in the AppDelegate.m file: 并在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
}

The only thing that I haven't got working is that if I change the data of the document on the iPad, the Mac app doesn't call the readFromData method for to update from iCloud, does anyone know what I am missing? 我唯一没有工作的是,如果我在iPad上更改文档的数据,Mac应用程序不会调用readFromData方法从iCloud更新,有没有人知道我缺少什么?

On iOS, the equivalent method, loadFromContents , is called automatically on every change of the UIDocument in iCloud. 在iOS上,在iCloud中每次更改UIDocument都会自动调用等效方法loadFromContents On OS X the readFromData is called once on load but never called again. 在OS X上, readFromData在加载时调用一次,但从未再次调用。

Hope my code can help, for me it is working one way from Mac to iPad. 希望我的代码可以提供帮助,对我而言,它是从Mac到iPad的一种方式。

I think NSMetadataQueryDidUpdateNotification is what you are looking for to detect document update. 我认为您正在寻找NSMetadataQueryDidUpdateNotification来检测文档更新。

This can be used just like NSMetadataQueryDidFinishGatheringNotification . 这可以像NSMetadataQueryDidFinishGatheringNotification一样NSMetadataQueryDidFinishGatheringNotification

If you are dealing with files in addition to core data. 如果您正在处理除核心数据之外的文件。 Here is a better tutorial 这是一个更好的教程

http://samvermette.com/312 http://samvermette.com/312

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM