19

我在 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 Photos 下删除已保存照片的自定义相册 3. 安装您的应用程序 4. 如果您使用不会创建或存储它们的应用程序拍照或录制视频。如果您查看 iOS 相册下的自定义相册,则不存在自定义相册,并且不存在使用该应用拍摄的照片/视频。

4

6 回答 6

11

我之前的回答是错误的。我还没有真正测试过。我终于弄清楚必须做什么,这很困难,但我做到了。这是我必须做的让我的应用程序在 iOS 7.xX 和 iOS 8.Xx 上运行并创建一个以前被应用程序删除的自定义相册 -->

  1. 我写了两段代码:一段在 iOS 8.xx 上使用 Photos 框架,另一段在 iOS 7.xx 上使用 AssetsLibrary 框架

  2. Sp 该应用程序可以在两个 iOS 版本上运行,我将应用程序链接到 Photos 框架,但随后将其从必需更改为可选,因此它不会在 iOS 7.xx 上加载

  3. 因为在 iOS 7.xx 上无法在运行时直接调用 Photos 框架代码,所以我不得不对其进行更改,以便它在运行时动态加载类、函数(和块!)

这是在 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);
   }];
}
于 2014-10-08T17:41:50.423 回答
3

使用 Adam 的回答和 Marin Todorov 的 ALAssetsLibrary 上的类别,ALAssetsLibrary+CustomPhotoAlbum 创建相册,并将照片放入其中,下面的代码替换了该类别中的主要 workHorse,它适用于 iOS7 设备和 iOS 8.1 设备,供需要的人使用两者兼得。

它在未知类上给出了两个关于 performSelector 的警告,任何改进都值得赞赏:

(它不会从您没有创建的共享相册中复制照片,并且会失败并显示消息,那里的任何增强功能也会很好)

1)添加“照片”框架,设置为“可选”

2) 包括导入行#import <Photos/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's 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's 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];
}
于 2014-10-24T20:29:28.827 回答
2

您可以尝试我的以下方法为 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");
    }];
}}
于 2015-04-08T09:34:28.677 回答
1

只是想更新我应该早点更新的每个人,但我有点忙于工作。此问题是/曾经是 iOS 8 的问题,但已在 iOS 8.0.2 中修复,因此您需要做的就是将您的 iOS 更新到 iOS 8.0.2

于 2014-09-28T20:40:01.637 回答
1

我使用下面的代码来检查特定相册是否存在,如果不存在,则创建它并向其中添加几个图像。从 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...");
    }];
}
于 2015-07-08T11:54:36.593 回答
0

由于上述建议都没有帮助我,这就是我解决将资产(照片)保存到自定义相册名称的问题的方法。此代码:“fetchCollectionResult.count==0”专门处理当您删除自定义相册并尝试再次保存时的情况,因为我认为 fetchCollectionResult 可能不再为“nil”。您也可以轻松更改此设置以支持保存视频/电影。

此代码仅适用于 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);
     }];
}
于 2014-12-24T08:32:06.050 回答