在不耗尽内存的情况下检索图像

Posted

技术标签:

【中文标题】在不耗尽内存的情况下检索图像【英文标题】:Retrieve Images Without Running Out Of Memory 【发布时间】:2016-01-26 05:54:11 【问题描述】:

我正在尝试从用户的相机胶卷中检索图像,但遇到了内存不足的问题。我一次加载 50 张图像,但不幸的是,在几次加载后,它会耗尽内存并崩溃。我尝试将整个语句包装在自动释放池中,但事实证明这并不有效。这是我的代码...

func retrieveImages(thumbnail: Bool, indexOfLibrary: Int) 
    /* Retrieve the items in order of modification date, ascending */
    var indexSet: NSIndexSet!

    let options = PHFetchOptions()

    options.sortDescriptors = [NSSortDescriptor(key: "creationDate",
        ascending: false)]

    /* Then get an object of type PHFetchResult that will contain
    all our image assets */
    let assetResults = PHAsset.fetchAssetsWithMediaType(.Image,
        options: options)

    if totalPostsCounted == false 
        assetResults.enumerateObjectsUsingBlock  (object: AnyObject!, count: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
            if object is PHAsset 
                self.totalPosts = count
             else 
                self.totalPostsCounted = true
            
        
    

    if thumbnail == true 
        if totalPosts - libraryImageThumbnails.count < 50 
            allImagesLoaded = true
         else 
            if firstTimeLoadedThumb == true 

             else 
                firstTimeLoadedThumb = true

            
        

     else 
        if totalPosts - libraryImages.count < 50 
            allImagesLoaded = true
         else 
            if firstTimeLoaded == true 
             else 
                firstTimeLoaded = true

            
        


    


    if thumbnail == true 
        fiftyIncrementThumb = fiftyIncrementThumb + 50
        increment = fiftyIncrementThumb
     else 
        fiftyIncrement = fiftyIncrement + 50
        increment = fiftyIncrement
    

    let imageManager = PHCachingImageManager()
    autoreleasepool  () -> () in

        assetResults.enumerateObjectsUsingBlock  (object, count: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
            if object is PHAsset 

                var imageSize: CGSize!

                var array: NSArray!

                if thumbnail == true 
                    array = self.libraryImageThumbnails
                 else 
                    array = self.libraryImages
                
                autoreleasepool 
                    if count >= array.count && count <= increment 
                        if thumbnail == true 
                            imageSize = CGSize(width: 100, height: 100)

                         else 
                            imageSize = CGSize(width: self.cameraView.bounds.width, height: self.cameraView.bounds.height)

                        

                        let asset = object as! PHAsset
                        let options = PHImageRequestOptions()
                        options.deliveryMode = .FastFormat
                        options.synchronous = true

                        imageManager.requestImageForAsset(asset,
                            targetSize: imageSize,
                            contentMode: .AspectFill,
                            options: options,
                            resultHandler:  (image, _: [NSObject : AnyObject]?) -> Void in
                                if thumbnail == true 
                                    self.libraryImageThumbnails.append(image!)
                                 else 
                                    self.libraryImages.append(image!)
                                
                        )
                    
                
            
        


    



我也试过这个,它返回 nil 并崩溃了......

    let library = ALAssetsLibrary()
        library.enumerateGroupsWithTypes(ALAssetsGroupAll, usingBlock:  (group: ALAssetsGroup!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in

            group.enumerateAssetsUsingBlock( (asset, count: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
                if asset != nil 
                    self.libraryImageThumbnails.append(asset)
                    self.collectionTable.reloadData()

                

            )
            , failureBlock:  (error: NSError!) -> Void in

        )

如果您需要更多信息,请告诉我!谢谢!

【问题讨论】:

您需要做的是获取图像的 url,然后使用来自该 url 的dispatch_async 将图像加载到后台队列中。 @DhaivatVyas 如何使用文件 URL 从我的相机胶卷中检索图像? 【参考方案1】:

这是我在一个项目中所做的可能会有所帮助的事情:

一些属性:

let requestOptions = PHImageRequestOptions()
let fetchOptions = PHFetchOptions()
let cachingImageManager = PHCachingImageManager()
var assets: [PHAsset] = [] 
    willSet 
        cachingImageManager.stopCachingImagesForAllAssets()
    

    didSet 
        cachingImageManager.startCachingImagesForAssets(assets,
            targetSize: PHImageManagerMaximumSize,
            contentMode: .AspectFit,
            options: self.requestOptions
        )
    



func fetchPhotos() 
    requestOptions.resizeMode = PHImageRequestOptionsResizeMode.Exact
    requestOptions.version = .Current
    requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat
    requestOptions.synchronous = true

    fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: false)]
    if #available(ios 9.0, *) 
        fetchOptions.fetchLimit = 50
     else 

        // Fallback on earlier versions
    

    fetchResults = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)
    guard let fetchResults = fetchResults else 
        print("No PHAssets")
        return
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0))  [weak self] in
        fetchResults.enumerateObjectsUsingBlock object, index, stop in
            let asset = object as! PHAsset
            self?.assets.append(asset)
        
        dispatch_async(dispatch_get_main_queue()) 
            self?.photoCollectionView.reloadData()
        
    

【讨论】:

太棒了。乐于助人!【参考方案2】:

试试这段代码,确保你导入&lt;AssetsLibrary/AssetsLibrary.h&gt;,并将你的部署目标设为7.1。

Objective-C 代码

NSMutableArray *imageArray=[[NSMutableArray alloc] init];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop)


    [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
     
         if (asset) 
             [imageArray addObject:asset];
             NSLog(@"imageArray :: %@",imageArray);
         
     ];
 failureBlock:^(NSError *error) 
    NSLog(@"error :: %@",error);
];

Swift 代码

var imageArray: [AnyObject] = [AnyObject]()
var library: ALAssetsLibrary = ALAssetsLibrary()

   library.enumerateGroupsWithTypes(ALAssetsGroupSavedPhotos, usingBlock: (group: ALAssetsGroup, stop: Bool) -> Void in
    group.enumerateAssetsUsingBlock((asset: ALAsset, index: Int, stop: Bool) -> Void in
        if asset != nil 
            imageArray.append(asset)
            NSLog("imageArray :: %@", imageArray)
        
   )
, failureBlock: (error: NSError) -> Void in
NSLog("error :: %@", error!)
)

结果:

查看以下网址以供参考

https://***.com/a/15570221/4101371

https://***.com/a/25732673/4101371

https://***.com/a/32472476/4101371

您还可以使用 iOS 8 及更高版本的照片框架。 photos Framework

希望它会有所帮助。

【讨论】:

我刚刚尝试了其中一个建议,并编辑了我的问题以显示我这样做时发生了什么。 嗯,由于某种原因,当我尝试它可以工作时,但是当我尝试在 cellForRow 中设置图像时它崩溃了。【参考方案3】:

设置下面的代码对我来说可以限制获取

let assetFetchOptions = PHFetchOptions()
assetFetchOptions.fetchLimit = 50

然后我只检索到 50 张照片,而我朋友的手机上只有 15,000 张!!

【讨论】:

以上是关于在不耗尽内存的情况下检索图像的主要内容,如果未能解决你的问题,请参考以下文章

如何在不耗尽内存的情况下运行大型 Mahout 模糊 kmeans 聚类?

如何使用 Python Ray 在不耗尽内存的情况下并行处理大量数据?

如何在不耗尽内存的情况下部署包含 130,000 多个条目的脚本

Google Big Query + PHP -> 如何在不耗尽内存的情况下获取大型数据集

在不耗尽 RAM 的情况下使用并发期货

如何在不耗尽电池的情况下监控 MPMoviePlayerController 播放进度?