База данных AssetsLibrary, разбитая на iOS 8
У меня возникла проблема с iOS 8 с базой библиотек объектов, которая, как представляется, является ошибкой в iOS 8. Если я создаю альбом под названием "MyMedia", а затем удалю его, тогда, когда я снова попытаюсь создать альбом, этот фрагмент кода ниже возвращает "nil", указывающий, что альбом "MyMedia" существует, хотя это не так, потому что я удалил его с помощью приложения "Фото".
__block ALAssetsGroup *myGroup = nil;
__block BOOL addAssetDone = false;
NSString *albumName = @"MyMedia";
[assetsLib addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
myGroup = group;
addAssetDone = true;
} failureBlock:^(NSError *error) {
NSLog( @"failed to create album: %@", albumName);
addAssetDone = true;
}];
while (!addAssetDone) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05f]];
}
return myGroup; // returns nil if group has previously been created and then deleted
Этот же метод работает при создании нового альбома "MyMedia2". Кто-нибудь еще испытал эту проблему и знал об обходном пути или решении? Это единственное решение для перехода к новой структуре "Фотографии", или я делаю что-то неправильное здесь? Обратите внимание, что этот код всегда работает на iOS7.X
На самом деле шаги по воспроизведению этой проблемы следующие: > 1. Удалите приложение, которое снимает фотографии и сохраняет их в пользовательский альбом.
2. В разделе "Фото iOS" удалите пользовательский альбом, в котором были сохранены фотографии.
3. Установите приложение
4. Если вы снимаете или записываете видео с помощью приложения, оно не создает их и не сохраняет. Если вы просматриваете альбомы iOS Photos, пользовательский альбом один не существует, и ни одно из изображений/видео, снятых с помощью приложения, не существует.
Ответы
Ответ 1
Мой предыдущий ответ был неправильным. Я не проверял его. Я, наконец, понял, что нужно делать, и это было сложно, но я получил его на работу. Это то, что мне нужно было сделать, чтобы мое приложение запускалось на iOS 7.x.X и iOS 8.X.x и создало пользовательский альбом, который ранее был удален приложением →
-
Я написал два куска кода: тот, который использует фреймворк на iOS 8.x.x и тот, который использует структуру AssetsLibrary на iOS 7.x.x
-
Sp приложение могло работать на обеих версиях iOS, я связал приложение с фреймворком, но затем изменил его с обязательным на необязательный, чтобы он не был загружен на iOS 7.xx
-
Поскольку код фреймворка Фотографии не мог быть вызван непосредственно во время выполнения на iOS 7.xx, мне пришлось изменить его, чтобы он динамически загружал классы, функции (и блоки!) динамически во время выполнения
Вот фрагмент кода, который работает при работе на iPhone. Это тоже должно работать в симуляторе →
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
if (PHPhotoLibrary_class) {
/**
*
iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(@"Error creating album: %@", error);
}
}];
*/
// dynamic runtime code for code chunk listed above
id sharedPhotoLibrary = [PHPhotoLibrary_class performSelector:NSSelectorFromString(@"sharedPhotoLibrary")];
SEL performChanges = NSSelectorFromString(@"performChanges:completionHandler:");
NSMethodSignature *methodSig = [sharedPhotoLibrary methodSignatureForSelector:performChanges];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:methodSig];
[inv setTarget:sharedPhotoLibrary];
[inv setSelector:performChanges];
void(^firstBlock)() = ^void() {
Class PHAssetCollectionChangeRequest_class = NSClassFromString(@"PHAssetCollectionChangeRequest");
SEL creationRequestForAssetCollectionWithTitle = NSSelectorFromString(@"creationRequestForAssetCollectionWithTitle:");
[PHAssetCollectionChangeRequest_class performSelector:creationRequestForAssetCollectionWithTitle withObject:albumName];
};
void (^secondBlock)(BOOL success, NSError *error) = ^void(BOOL success, NSError *error) {
if (success) {
[assetsLib enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([albumName isEqualToString:name]) {
groupFound = true;
handler(group, nil);
}
}
} failureBlock:^(NSError *error) {
handler(nil, error);
}];
}
if (error) {
NSLog(@"Error creating album: %@", error);
handler(nil, error);
}
};
// Set the success and failure blocks.
[inv setArgument:&firstBlock atIndex:2];
[inv setArgument:&secondBlock atIndex:3];
[inv invoke];
}
else {
// code that always creates an album on iOS 7.x.x but fails
// in certain situations such as if album has been deleted
// previously on iOS 8...x. .
[assetsLib addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
handler(group, nil);
} failureBlock:^(NSError *error) {
NSLog( @"Failed to create album: %@", albumName);
handler(nil, error);
}];
}
Ответ 2
Используя ответ Адама и категорию Марин Тодоров в ALAssetsLibrary, ALAssetsLibrary + CustomPhotoAlbum для создания фотоальбомов и размещения в них фотографий, этот код ниже заменяет основной workHorse в этой категории, он работает как на устройствах iOS7, так и на устройствах iOS 8.1 для те, кому нужно иметь оба.
он дает два предупреждения о performSelector в неизвестном классе, хотя любые улучшения оцениваются:
(он не будет копировать фотографию из общего альбома, который вы не создали, и сработает с сообщением, любые улучшения там тоже будут хороши)
1) добавьте фреймы "Фотографии", установите "Необязательный"
2) включают строку импорта #import < Фотографии /PHPhotoLibrary.h >
//----------------------------------------------------------------------------------------
- (void)addAssetURL:(NSURL *)assetURL
toAlbum:(NSString *)albumName
completion:(ALAssetsLibraryWriteImageCompletionBlock)completion
failure:(ALAssetsLibraryAccessFailureBlock)failure
{
NSLog();
__block BOOL albumWasFound = NO;
//-----------------------------------------
ALAssetsLibraryGroupsEnumerationResultsBlock enumerationBlock;
enumerationBlock = ^(ALAssetsGroup *group, BOOL *stop)
{
NSLog(@" ALAssetsLibraryGroupsEnumerationResultsBlock");
// Compare the names of the albums
if ([albumName compare:[group valueForProperty:ALAssetsGroupPropertyName]] == NSOrderedSame)
{
NSLog(@"--------------Target album is found");
// Target album is found
albumWasFound = YES;
// Get a hold of the photo asset instance
// If the user denies access to the application, or if no application is allowed to
// access the data, the failure block is called.
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[self _assetForURLResultBlockWithGroup:group
assetURL:assetURL
completion:completion
failure:failure];
[self assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
// Album was found, bail out of the method
*stop = YES;
}
if (group == nil && albumWasFound == NO)
{
NSLog(@"--------------Target album does not exist");
// Photo albums are over, target album does not exist, thus create it
// Since you use the assets library inside the block,
// ARC will complain on compile time that there’s a retain cycle.
// When you have this – you just make a weak copy of your object.
ALAssetsLibrary * __weak weakSelf = self;
// If iOS version is lower than 5.0, throw a warning message
if (! [self respondsToSelector:@selector(addAssetsGroupAlbumWithName:resultBlock:failureBlock:)])
{
NSLog(@"--------------Target album does not exist and does not respond to addAssetsGroupAlbumWithName");
} else {
NSLog(@"--------------Target album does not exist addAssetsGroupAlbumWithName");
// ----------- PHPhotoLibrary_class will only be non-nil on iOS 8.x.x -----------
Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
NSLog(@"PHPhotoLibrary_class %@ ", PHPhotoLibrary_class);
if (PHPhotoLibrary_class)
{
NSLog(@"iOS8");
// --------- dynamic runtime code -----------
id sharedPhotoLibrary = [PHPhotoLibrary_class performSelector:NSSelectorFromString(@"sharedPhotoLibrary")];
NSLog(@"sharedPhotoLibrary %@ ", sharedPhotoLibrary);
SEL performChanges = NSSelectorFromString(@"performChanges:completionHandler:");
NSMethodSignature *methodSig = [sharedPhotoLibrary methodSignatureForSelector:performChanges];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:methodSig];
[inv setTarget:sharedPhotoLibrary];
[inv setSelector:performChanges];
void(^firstBlock)() = ^void()
{
NSLog(@"firstBlock");
Class PHAssetCollectionChangeRequest_class = NSClassFromString(@"PHAssetCollectionChangeRequest");
SEL creationRequestForAssetCollectionWithTitle = NSSelectorFromString(@"creationRequestForAssetCollectionWithTitle:");
NSLog(@"PHAssetCollectionChangeRequest_class %@ ", PHAssetCollectionChangeRequest_class);
[PHAssetCollectionChangeRequest_class performSelector:creationRequestForAssetCollectionWithTitle withObject:albumName];
};
void (^secondBlock)(BOOL success, NSError *error) = ^void(BOOL success, NSError *error)
{
NSLog(@"secondBlock");
if (success)
{
NSLog(@"success");
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *fullStop)
{
if (group)
{
NSLog(@"group %@ ", group);
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([albumName isEqualToString:name])
{
NSLog(@"[albumName isEqualToString:name] %@ ", name);
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[self _assetForURLResultBlockWithGroup:group
assetURL:assetURL
completion:completion
failure:failure];
[self assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
*fullStop = YES;
}
}
} failureBlock:failure];
}
if (error)
{
NSLog(@"Error creating album: %@", error);
}
};
// Set the success and failure blocks.
[inv setArgument:&firstBlock atIndex:2];
[inv setArgument:&secondBlock atIndex:3];
[inv invoke];
} else {
NSLog(@"iOS7");
[self addAssetsGroupAlbumWithName:albumName resultBlock:^(ALAssetsGroup *createdGroup)
{
// Get the photo instance, add the photo to the newly created album
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[weakSelf _assetForURLResultBlockWithGroup:createdGroup
assetURL:assetURL
completion:completion
failure:failure];
[weakSelf assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
}
failureBlock:failure];
}
}
// Should be the last iteration anyway, but just in case
*stop = YES;
}
};
// Search all photo albums in the library
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:enumerationBlock
failureBlock:failure];
}
Ответ 3
Вы можете попробовать My below Method для создания альбома для iOS 7 и iOS 8
#define PHOTO_ALBUM_NAME @"AlbumName Videos"
#pragma mark - Create Album
-(void)createAlbum{
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
if (PHPhotoLibrary_class) {
// iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(@"Error creating album: %@", error);
}else{
NSLog(@"Created");
}
}];
}else{
[self.library addAssetsGroupAlbumWithName:PHOTO_ALBUM_NAME resultBlock:^(ALAssetsGroup *group) {
NSLog(@"adding album:'Compressed Videos', success: %s", group.editable ? "YES" : "NO");
if (group.editable == NO) {
}
} failureBlock:^(NSError *error) {
NSLog(@"error adding album");
}];
}}
Ответ 4
Просто хотел обновить всех, кого я должен был обновить раньше, но у меня появилось много заботы о работе. Эта проблема связана с iOS 8, но была исправлена с iOS 8.0.2, поэтому все, что вам нужно сделать, чтобы исправить это, - это обновление iOS до iOS 8.0.2.
Ответ 5
Я использовал приведенный ниже код, чтобы проверить, существует ли конкретный альбом, и если он его не существует, создайте его и добавьте к нему пару изображений. После создания объекта из UIImage я использую его заполнитель, чтобы добавить его в альбом, не выходя из блока.
//Will enter only in iOS 8+
Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
if (PHPhotoLibrary_class)
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
{
//Checks for App Photo Album and creates it if it doesn't exist
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title == %@", kAppAlbumName];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:fetchOptions];
if (fetchResult.count == 0)
{
//Create Album
PHAssetCollectionChangeRequest *albumRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:kAppAlbumName];
//Add default photos to it
NSMutableArray *photoAssets = [[NSMutableArray alloc] init];
for (UIImage *image in albumDefaultImages)
{
PHAssetChangeRequest *imageRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
[photoAssets addObject:imageRequest.placeholderForCreatedAsset];
}
[albumRequest addAssets:photoAssets];
}
}
completionHandler:^(BOOL success, NSError *error)
{
NSLog(@"Log here...");
}];
}
Ответ 6
Как ни одно из приведенных выше предложений не помогло мне, так я решил решить проблемы с сохранением активов (фотографий) до имени пользовательского альбома.
Этот код: "fetchCollectionResult.count == 0" специально обрабатывает ситуацию, когда вы удалили свой собственный альбом один раз и снова пытаетесь сохранить его, так как я полагаю, что fetchCollectionResult может перестать быть "ноль".
Вы можете легко изменить это, чтобы поддерживать сохранение видео/фильмов.
Этот код предназначен только для iOS 8!
Вы должны быть уверены, что не будете называть его, если устройство работает в более ранних версиях!
#define PHOTO_ALBUM_NAME @"MyPhotoAlbum"
NSString* existingAlbumIdentifier = nil;
-(void)saveAssetToAlbum:(UIImage*)myPhoto
{
PHPhotoLibrary* photoLib = [PHPhotoLibrary sharedPhotoLibrary];
__block NSString* albumIdentifier = existingAlbumIdentifier;
__block PHAssetCollectionChangeRequest* collectionRequest;
[photoLib performChanges:^
{
PHFetchResult* fetchCollectionResult;
if ( albumIdentifier )
fetchCollectionResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[albumIdentifier] options:nil];
// Create a new album
if ( !fetchCollectionResult || fetchCollectionResult.count==0 )
{
NSLog(@"Creating a new album.");
collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
albumIdentifier = collectionRequest.placeholderForCreatedAssetCollection.localIdentifier;
}
// Use existing album
else
{
NSLog(@"Fetching existing album, of #%d albums found.", fetchCollectionResult.count);
PHAssetCollection* exisitingCollection = fetchCollectionResult.firstObject;
collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:exisitingCollection];
}
NSLog(@"Album local identifier = %@", albumIdentifier);
PHAssetChangeRequest* createAssetRequest;
createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:myPhoto];
[collectionRequest addAssets:@[createAssetRequest.placeholderForCreatedAsset]];
}
completionHandler:^(BOOL success, NSError *error)
{
if (success)
{
existingAlbumIdentifier = albumIdentifier;
NSLog(@"added image to album:%@", PHOTO_ALBUM_NAME);
}
else
NSLog(@"Error adding image to album: %@", error);
}];
}