Кажется, я не могу получить все фотографии в определенном пользователем альбоме "Фотографии" на Mac.Иногда я получаю большинство из них, но у меня также есть альбом в фотографиях, из которого я не получаю ни одного.Я считаю, что это вызвано iCloud;Я включил «Библиотеку фотографий iCloud» в настройках «Фотографии».
Я использую интерфейс MLMediaLibrary ( Media Library Framework ) в macOS 10.13, но я счастлив использовать любую другуюAPI, если он работает лучше.Обратите внимание, что я не спрашиваю о том, как использовать фреймворки на iOS.Я работаю на Mac.
Я уже искал в Интернете, я также посмотрел на отличный ответ на аналогичный вопрос здесь, на SO.Кроме того, я посмотрел на этот пример от 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];
}