我似乎无法在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];
}