【问题标题】:AssetsLibrary framework broken on iOS 8iOS 8 上的 AssetsLibrary 框架损坏
【发布时间】:2014-11-18 03:19:44
【问题描述】:

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

【问题讨论】:

  • 您可能想开始编写照片框架。我只是,多么痛苦……
  • 如果我使用 Xcode 6 和 Photos 框架构建应用程序,我仍然可以在安装了 7.X 的设备上运行它吗?
  • 不,它仅适用于 iOS8。是的,这很困难,本质上你必须使用两个 API 进行编码
  • 遇到同样的问题,太糟糕了!
  • 同样的问题?我可以完全删除资产,还是永远无法重新创建具有该名称的专辑?

标签: objective-c ios7 ios8 alassetslibrary photosframework


【解决方案1】:

我之前的回答不正确。我还没有真正测试过。我终于弄清楚必须做什么,这很困难,但我得到了它的工作。这就是我必须做的让我的应用程序在 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 框架代码,我不得不对其进行更改,以便在运行时动态加载类、函数(和块!)

    李>

这是在 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);
   }];
}

【讨论】:

  • @Kjuly : handler(group, nil);给我声明错误请给我声明代码。
  • @ChiragPipaliya 也许你可以试试这个库:github.com/Kjuly/ALAssetsLibrary-CustomPhotoAlbum。 Adam 已经为 iOS 8 合并了这个修复。:)
  • handler(group, nil) 是一个完成块,您提供它作为具有方法签名的参数:^(void)(ALAssetsGroup*, NSError*)
  • 我建议不要使用 NSSelectorFromString 而只使用 @selector({method name goes here})。这样你就不容易出现错别字。让编译器帮你!
  • @AdamFreeman 您是否尝试过在 ios7 中获取所有照片?我得到了所有照片,但没有得到相册创建日期和事件名称。我想开发我的应用程序,就像我们在 ios8 的 iPhoto 应用程序中看到的那样显示所有即时数据。在 ios8 中,它显示所有时刻并且工作正常,但在 ios7 中,它无法使用 PHAsset 获取照片。
【解决方案2】:

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

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

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

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

2) 包含导入行#import

    //----------------------------------------------------------------------------------------
- (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];
}

【讨论】:

    【解决方案3】:

    你可以试试我下面的方法为 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

      【讨论】:

      • 谢谢老兄。我正在拔头发。但是我在 Xcode 6.0.1 中运行 iOS 8 iPhone 6 模拟器时仍然遇到同样的问题。我应该如何解决这个问题?
      • 在 8.3 中面临相同的情况,您是否面临相同的情况?
      • 我还没有用 8.3 测试过。你在 8.3 上看到了什么?经过大量测试和使用不同的资产库框架功能后,唯一真正需要为 8.0、8.0.1 和 8.0.2 更改的代码是创建自定义相册。我不记得我使用的原始 AL 功能是什么但不起作用,但我只是使用了一些其他的功能,这些功能确实有效,解决了我除了创建自定义相册之外的所有其他问题。
      【解决方案5】:

      我使用下面的代码来检查特定相册是否存在,如果不存在,则创建它并向其中添加几张图像。从 UIImage 创建 Asset 后,我​​使用它的占位符将其添加到相册而不离开块。

      //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 可能不再为“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-21
          • 1970-01-01
          • 1970-01-01
          • 2021-08-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多