MacOS:无法使用MLMediaLibrary获取Apple Photos相册中的所有照片

时间:2018-10-11 10:04:47

标签: macos cocoa

我似乎无法在Mac上检索用户定义的相册中的所有照片。 有时候,我得到的大多数,但我在“照片”中也有一张专辑,但没有得到。我相信这是由iCloud引起的;我已经在“照片”设置中打开了“ iCloud照片库”。

我正在macOS 10.13上使用MLMediaLibrary接口(Media Library Framework),但是如果它能更好地工作,我很乐意使用任何其他API。 请注意,我不是在询问如何在iOS上使用框架。我正在Mac上工作。

我已经在网上搜索过,我也在此处搜索了类似问题的great answer。另外,我看着这个example from Apple

实际上,即使示例代码也无法显示全部照片。我相信这是因为我已在“照片”设置中打开了“ iCloud照片库”。当我右键单击某个相册并“将原件下载到此Mac”时,过一会儿,我的确会用我的代码从该相册中获取所有照片。

所以,问题是:如何确保特定专辑中的所有原件都已在Mac上下载,或者如何从我的代码中完成?

在下面,您可以找到我到目前为止提出的代码。它是完整源代码(我正在编写的屏幕保护程序)的非常完整的摘录,因此它应该使您清楚地知道它是如何工作的。 在初始化期间,我检索了用户定义的顶级专辑的列表。 然后,当用户选择其中一个时,我找到了相应的媒体组对象(相册),然后从中检索所有图像。

非常感谢您的帮助,建议或指示。

最好的问候,加布里埃尔

static char * MediaLibraryLoaded = "MediaLibraryLoaded";         // just IDs for the KVO
static char * RootMediaGroupLoaded = "RootMediaGroupLoaded";
static char * MediaObjects = "MediaObjects";

- (id) initWithFrame: (NSRect) frameRect isPreview: (BOOL) preview
{
[...]
    // start loading all Photos albums (has to be done asynchronously because MLMediaLibrary wants it that way)
    albums_ = [[NSMutableArray alloc] init];
    NSDictionary *options = @{
                              MLMediaLoadSourceTypesKey: @(MLMediaSourceTypeImage),
                              MLMediaLoadIncludeSourcesKey: @[MLMediaSourcePhotosIdentifier]
                              };
    mediaLibrary_ = [[MLMediaLibrary alloc] initWithOptions: options];
    [mediaLibrary_ addObserver: self
                        forKeyPath: @"mediaSources"
                           options: 0
                           context: (__bridge void *) &MediaLibraryLoaded];     // take the address, which will be always unique, even in case of string coalescing
    [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier ];  // starts asynchronous loading
[...]
}


- (void) observeValueForKeyPath: (NSString *) keyPath   ofObject: (id) object
                         change: (NSDictionary *) change context: (void *) context
{
    MLMediaSource * mediaSource = [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier];

    // this stuff was initiated from initWithFrame:
    if ( context == &MediaLibraryLoaded )
    {
        [mediaSource addObserver: self
                      forKeyPath: @"rootMediaGroup"
                         options: 0
                         context: (__bridge void *) &RootMediaGroupLoaded];
        [mediaSource rootMediaGroup];                                           // start next phase: load groups
    }
    else if ( context == &RootMediaGroupLoaded )
    {
        MLMediaGroup *albums = [mediaSource mediaGroupForIdentifier: @"TopLevelAlbums"];

        for ( MLMediaGroup * album in albums.childGroups )
        {
            NSString * type = [album.attributes objectForKey: @"typeIdentifier"];                   // only include user-defined albums
            if ( type && [type isEqualToString: @"com.apple.Photos.Album"] )                        // magic constant found by printf, couldn't find the proper pre-defined variable
            {
                NSString * albumName = [album.attributes objectForKey: @"name"];
                [albums_ addObject: album ];
            }
        }

        [mediaSource removeObserver: self forKeyPath: @"rootMediaGroup"];
        [mediaLibrary_ removeObserver: self forKeyPath: @"mediaSources"];
    }
    else if ( context == &MediaObjects )                // initiated by scanIPhotoPaths
    {
        NSArray * mediaObjects = album_.mediaObjects;                                             // album_ has been set by scanIPhotoPaths:
        for ( MLMediaObject * mediaObject in mediaObjects )
        {
            if ( mediaObject.mediaType != MLMediaTypeImage )                    // even if I remove this, I don't get all
                continue;                                   // media objects in the album (usually)
            NSURL * url  = mediaObject.URL;
            [photoPaths_ addObject: url.path];
        }

        [self scanIPhotoPathsFinish];
    }
}


- (void) scanIPhotoPaths: (NSString *) album_name
{
[...]
    // find album by name
    album_ = nil;
    for ( MLMediaGroup * album in albums_ )
    {
        if ( [album_name isEqualToString: [album.attributes objectForKey: @"name"] ] )
        {
            album_ = album;
            break;
        }
    }

    // if not found, return to default (can't happen)
    if ( ! album_ )
    {
        return;
    }

    photoPaths_ = [[NSMutableArray alloc] init];

    // we have to use the KVO, because right now, [album_.mediaObjects count] == 0
    [album_ addObserver: self
             forKeyPath: @"mediaObjects"
                options: 0
                context: (void *) &MediaObjects];

    [album_ mediaObjects];
}

0 个答案:

没有答案