Мне нужно отобразить структуру альбома Apple Photos в моем приложении на macOS. Единственный способ сделать это - MediaLibrary Framework. Я могу без проблем пройти по древовидной структуре, используя класс MLMediaGroup. Но наблюдение за изменениями в нем вызывает у меня недоумение. Я ожидаю, что мне нужно будет подписаться на KVO-notificatios для каждой отдельной медиа-группы и наблюдать за изменениями в атрибутах.
Но в действительности, когда я создаю новый альбом / папку в Фото, я получаю уведомление о том, что rootMediaGroup изменилась, и адреса этой группы, а также всех дочерних групп также изменились. Это кажется странным, потому что теперь мне нужно перестроить всю иерархию альбомов. Это похоже на просмотр изменений каталога и получение непрозрачных уведомлений типа «что-то в файловой системе изменилось» без дополнительной информации каждый раз, когда пользователь изменяет каталог где-то глубоко внутри $ HOME.
Я использую target-c (на самом деле мне нужно интегрировать его с c ++), хотя быстрые примеры также могут дать мне подсказку. Ниже я приведу минимальный пример для иллюстрации вопроса.
PhotosObserver.h
#import <Foundation/Foundation.h>
#import <MediaLibrary/MediaLibrary.h>
@interface PhotosObserver: NSObject
{
@private
MLMediaLibrary *ml;
MLMediaSource *src;
MLMediaGroup *root;
}
@property(nonatomic, retain, nullable, readonly) MLMediaLibrary *ml;
@property(nonatomic, retain, nullable, readonly) MLMediaSource *src;
@property(nonatomic, retain, nullable, readonly) MLMediaGroup *root;
@end
PhotosObserver.m
#include "PhotosObserver.h"
static void* CTX_MEDIASOURCE = &CTX_MEDIASOURCE;
static void* CTX_MEDIAGROUP = &CTX_MEDIAGROUP;
static NSString* KPATH_SOURCES = @"mediaSources";
static NSString* KPATH_GROUPS = @"rootMediaGroup";
@implementation PhotosObserver
@synthesize ml;
@synthesize src;
@synthesize root;
-(id)init {
if(self = [super init]) {
self->ml = [[MLMediaLibrary alloc] init];
[self->ml addObserver: self forKeyPath:KPATH_SOURCES options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:CTX_MEDIASOURCE];
[self->ml mediaSources];
}
return self;
}
-(void)dealloc {
@try {
[self.ml removeObserver:self forKeyPath:KPATH_SOURCES context:CTX_MEDIASOURCE];
[self.src removeObserver:self forKeyPath:KPATH_GROUPS context:CTX_MEDIAGROUP];
}
@catch(NSException *) {}
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if(CTX_MEDIASOURCE == context)
{
NSLog(@"Loaded mediaSources");
self->src = [self->ml.mediaSources objectForKey:/*@"com.apple.Photos"*/MLMediaSourcePhotosIdentifier];
assert(self->src);
[self.src addObserver: self forKeyPath:KPATH_GROUPS options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:CTX_MEDIAGROUP];
[self.src rootMediaGroup];
}
else if(CTX_MEDIAGROUP == context)
{
MLMediaGroup *old = self->root;
if(!old)
NSLog(@"Loaded rootMediaGroup");
self->root = self.src.rootMediaGroup;
if(old && old != self.root)
{
NSLog(@"Oops, root group has changed: %@ -> %@", old, self.root);
}
}
}
@end
Когда я запускаю программу и создаю папку / альбом или переименовываю альбом в Фото, я получаю уведомление об изменении корневой группы. Почему-то я не получаю уведомления в 100% случаев, но в любом случае довольно часто.
В: Почему rootMediaGroup изменяется вообще, поскольку пользователь не может изменить его в пользовательском интерфейсе Photos?
В: Как отслеживать изменения без необходимости повторного сканирования всей иерархии MLMediaGroup после каждой небольшой пользовательской модификации?