在iOS 8上打破的AssetsLibrary框架

时间:2014-09-23 19:29:32

标签: objective-c ios7 ios8 alassetslibrary photosframework

我在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相册下查看,则自定义相册不存在,并且不存在使用该应用拍摄的所有照片/视频。

6 个答案:

答案 0 :(得分:11)

我之前的回答是不正确的。我还没有真正测试过它。我终于弄明白了要做什么,这很困难,但我得到了它的工作。这是我必须要做的就是让我的应用程序在iOS 7.x.X和iOS 8.X.x上运行并创建一个以前被应用程序删除的自定义相册 - >

  1. 我写了两个代码块:一个使用iOS 8.x.x上的Photos框架,另一个使用iOS 7.x.x上的AssetsLibrary框架

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

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

  4. 以下是在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);
       }];
    }
    

答案 1 :(得分:3)

使用Adam的答案,以及Marin Todorov在ALAssetsLibrary上的类别,ALAssetsLibrary + CustomPhotoAlbum来创建相册,并在其中放置照片,下面的代码替换了该类别中的主要工作主体,它可以在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'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];
}

答案 2 :(得分: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");
    }];
}}

答案 3 :(得分:1)

只是想更新我应该尽早更新的所有人,但我有点淹没了工作。这个问题是iOS 8的一个问题,但已经在iOS 8.0.2中得到修复,因此您需要做的就是将iOS更新为iOS 8.0.2

答案 4 :(得分:1)

我使用以下代码检查特定相册是否存在,如果不存在,请创建它并向其添加几个图像。从UIImage创建资产后,我使用其占位符将其添加到相册而不离开该块。

// from
vector.insert(data);
// to
insert_poc(vector, data);

答案 5 :(得分: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);
     }];
}