【问题标题】:How to Sync an NSDocument from Mac osx to iPad/iPhone with iCloud如何使用 iCloud 将 NSDocument 从 Mac osx 同步到 iPad/iPhone
【发布时间】:2012-02-20 10:03:23
【问题描述】:

我已经看到了 iOS 的 iCloud 文档示例代码,我用它来将 同步到 iCloud 和从 iCloud 同步,现在我正在尝试在没有 @ 的 Mac OSX 应用程序上将 iCloud 与 同步987654325@。

我尝试将UIDocument 更改为NSDocument,但与 同步的所有方法都不同。除了来自 的文档之外,我没有找到任何示例代码或教程,这非常令人困惑且写得不好。

例如,下面的方法,来自 iOS 上的 UIDocument 在 OS X 上的 NSDocument 中不存在:

//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 同步)?

【问题讨论】:

  • 并非所有人都觉得文档“令人困惑且写得不好”。
  • 我使用了文档,但它对我不起作用。
  • 另外 - 为什么不显示一些您尝试过的代码,而不是寻找可以剪切和粘贴的东西。你已经为 iOS 完成了 - 所以你必须对流程有所了解。
  • 给你,我从文档中粘贴了一些对我不起作用的代码。

标签: uidocument nsdocument icloud apple objective-c ios macos icloud nsdocument


【解决方案1】:

我设法让它工作了!这是我在 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 会在 iCloud 中 UIDocument 的每次更改时自动调用。在 OS X 上,readFromData 在加载时被调用一次,但不再被调用。

希望我的代码可以提供帮助,对我来说,它是从 Mac 到 iPad 的一种方式。

【讨论】:

  • @user1173374 您不应该在 StackOverflow 上的答案中提出更多问题。相反,开始一个新问题。在您的新问题中,您可以链接回此答案以供参考。
  • @Olof 我在这里发布了从 iPad 更新到 Mac 的问题:stackoverflow.com/questions/20984512/…
【解决方案2】:

我认为NSMetadataQueryDidUpdateNotification 是您要检测文档更新的对象。

这可以像NSMetadataQueryDidFinishGatheringNotification一样使用。

【讨论】:

    【解决方案3】:

    如果您正在处理除核心数据之外的文件。这里有一个更好的教程

    http://samvermette.com/312

    【讨论】:

      猜你喜欢
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-30
      • 2011-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多