如何在我的无处不在的容器中获取所有可用的持久存储?

Posted

技术标签:

【中文标题】如何在我的无处不在的容器中获取所有可用的持久存储?【英文标题】:How to get all available persistentStores in my ubiquityContainer? 【发布时间】:2013-11-25 11:05:14 【问题描述】:

在我的应用程序中,我有几个持久存储,用户可以删除和添加存储。我最近将 iCloud 添加到项目中,现在我需要知道哪些商店在启动时可用,以便我可以列出它们。以前这是由我在创建和删除商店时管理的数组处理的。但是现在可以创建或删除存储或单独的设备,我希望在我的 ubiquity 容器中获得所有可用的持久存储。这可能吗?

【问题讨论】:

【参考方案1】:

这是我用来查找新文件或已删除文件的代码。发表您的任何问题,我会尽力回复。

/*!  Creates and starts a metadata query for iCloud files

 */
- (void)createFileQuery 
    [_query stopQuery];

    if ([[CloudManager sharedManager] isCloudEnabled]) 
        if (_query) 
            [_query startQuery];
        
        else 
            _query = [[NSMetadataQuery alloc] init];

            [_query setSearchScopes:[NSArray arrayWithObjects:NSMetadataQueryUbiquitousDocumentsScope, NSMetadataQueryUbiquitousDataScope, nil]];
            NSString *str = @"*";
            [_query setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE %@", NSMetadataItemFSNameKey, str]];

            NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
            [notificationCenter addObserver:self selector:@selector(fileListReceived) name:NSMetadataQueryDidFinishGatheringNotification object:_query];
            [notificationCenter addObserver:self selector:@selector(fileListReceived) name:NSMetadataQueryDidUpdateNotification object:_query];
            [_query startQuery];
        
    



/*!  Gets called by the metadata query any time files change

 */
- (void)fileListReceived 
    //LOG(@"fileListReceived called.");

    bool found = NO;

    if ([self getNewiCloudDocs]) 
        //LOG(@"  New iCloud documents found!");
        found = YES;
    

    if ([self getDeletediCloudDocs]) 
        //LOG(@"  Deleted iCloud documents found!");
        found = YES;
    

    // Just check the local files again...
    if (found)
        [self updateList];

    return;



/*! Gets the list of files in the iCloud directory and compares against files we have locally
    and then creates new ones if required.  WARNING: files appear in iCloud before they appear
    locally when we are creating new documents so we must set a flag so we know to ignore any 
    new files that appear if we are busy creating a new document already.  Only applies if we
    have initiated creating a new document on this device!

    @return Returns true if any have been found
 */
- (bool)getNewiCloudDocs 
    //FLOG(@"getNewiCloudDocs called");
    bool found = NO;

    NSURL *iCloudDirectory = [[CloudManager sharedManager] iCloudCoreDataURL];

    //FLOG(@"  iCloudDirectory is %@", iCloudDirectory);

    // Get the top level directory names are these will represent all the iCloud documents
    NSArray* cloudDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:iCloudDirectory includingPropertiesForKeys:nil options:0 error:nil];

    //Now get an array of the local document names including any UUID because we want then to be unique
    NSMutableArray *localFileIDs = [[NSMutableArray alloc] init];

    for (NSURL *doc in _localDocuments) 
        [localFileIDs addObject:[doc lastPathComponent]];
    

    // Check if there are any we don't already have
    //FLOG(@"  iCloud Documents are:");
    for (NSURL* document in cloudDocuments) 
        //FLOG(@"   %@", [document lastPathComponent]);

        NSString *name = [document lastPathComponent];

        if (![localFileIDs containsObject:name]) 
            //FLOG(@"  new file found: %@", name);
            found = YES;
            [self createLocalCopyOfICloudFile: name];

        
    
    return found;

/*! Looks for files we have that are not in iCloud and are local.
    These have probably been deleted by some other device so remove them.

    @return Returns true if any have been found
 */
- (bool)getDeletediCloudDocs 
    //FLOG(@"getDeletediCloudDocs called");
    bool found = NO;

    NSURL *iCloudDirectory = [[CloudManager sharedManager] iCloudCoreDataURL];

    //Now get an array of the local document names including any UUID because we want then to be unique
    NSMutableArray *localFileIDs = [[NSMutableArray alloc] init];
    NSMutableArray *cloudFileIDs = [[NSMutableArray alloc] init];


    for (NSURL *doc in _localDocuments) 
        [localFileIDs addObject:[doc lastPathComponent]];
    

    // Get the top level directory names are these will represent all the iCloud documents
    NSArray* cloudDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:iCloudDirectory includingPropertiesForKeys:nil options:0 error:nil];
    if ([cloudDocuments count]) 

        //FLOG(@" %d documents found in iCloud", [cloudDocuments count]);
        //FLOG(@"   docs are: %@", cloudDocuments);
        for (NSURL* doc in cloudDocuments) 
            [cloudFileIDs addObject:[doc lastPathComponent]];
        

        // Check if there are documents that we have that are not in iCloud
        //FLOG(@"  Deleted iCloud Documents are:");
        for (NSURL* document in _localDocuments) 
            NSString *name = [document lastPathComponent];

            if (![cloudFileIDs containsObject:name]) 
                FLOG(@"  REMOVED iCloud file detected: %@", name);
                found = YES;
                [self removeLocalCopyOfiCloudFile: name];

            
        
     else 

        FLOG(@" no documents found in iCloud");
        FLOG(@" removing all local documents");

        for (NSURL* document in _localDocuments) 
            NSString *name = [document lastPathComponent];
            //FLOG(@"  removing local file %@", name);
            found = YES;
            [self removeLocalCopyOfiCloudFile: name];
        

    

    return found;


- (void)createLocalCopyOfICloudFile:(NSString *)fileName 

    if (!_creatingDocument) 
        NSURL* fileURL = [[[CloudManager sharedManager] documentsDirectoryURL] URLByAppendingPathComponent:fileName];

        [self.appDelegate createLocalCopyOfCloudFile:fileURL];
     else 
        LOG(@"Busy creating document so don't do anything!");
    


- (void)removeLocalFile:(NSString *)fileName 
    LOG(@"");
    FLOG(@"  REMOVING local copy of file: %@", fileName);
    NSURL* fileURL = [[[CloudManager sharedManager] documentsDirectoryURL] URLByAppendingPathComponent:fileName];
    [self deleteDocumentAtURL:fileURL];
    LOG(@"");


- (void)removeLocalCopyOfiCloudFile:(NSString *)fileName 
    LOG(@"");
    if (!_deletingDocument) 
        FLOG(@"  REMOVING local copy of DELETED iCloud file: %@", fileName);
        NSURL* fileURL = [[[CloudManager sharedManager] documentsDirectoryURL] URLByAppendingPathComponent:fileName];
        [self deleteLocalCopyOfiCloudDocumentAtURL:fileURL];
        LOG(@"");
     else 
        LOG(@"Busy deleting document so don't do anything!");
    

【讨论】:

【参考方案2】:

对 ubiquity 容器进行元数据扫描,并获取应用程序 ubiquity 容器 /CoreData 目录中所有目录的列表。这些目录应与通过 iCloud 同步的所有商店的 NSPersistentStoreUbiquityNameKey 对应。我似乎记得 Apple 的 wwdc2013 207 视频解释了这就是 Core Data/iCloud 集成的工作原理。

我使用由用户输入的文件名+'UUID'+uuid 组成的字符串作为 NSPersistentStoreUbiquityNameKey,以便在另一台设备上向用户显示相同的文件名。

我扫描这样的“新”文件是否存在,当我检测到一个时,我会自动构建商店的本地副本,同样,当我检测到文件已被删除时,我会删除本地自动存储。

请注意,我还存储有关文件的本地元数据,以便在打开文件时可以确定将正确的选项传递给 persistentStoreCoordinator。

如果您有兴趣,我可以发布用于扫描的代码。

注意:请记住,存储本身并不存储在 iCloud 中,只有事务日志存储,因此您需要构建本地存储并传入正确的 NSPersistentStoreUbiquityNameKey,然后 Core Data 将从 iCloud 导入事务日志。

【讨论】:

我根据link尝试了元数据方法,但在另一台设备上添加新文件时没有收到任何通知。 对不起,我忘了提到我使用元数据查询来触发目录扫描。请参阅实际代码的附加答案。希望这会有所帮助。

以上是关于如何在我的无处不在的容器中获取所有可用的持久存储?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Blob 存储中容器中所有文件夹的列表?

IBM Bluemix体验:Containers持久存储

如何使用 android 范围/共享存储获取可用空间?

POD崩溃时持久卷声明中的容器数据

cognito 用户会话被持久化,而不在本地存储中存储令牌

aws fargate 的持久存储解决方案 [关闭]