HTML5   发布时间:2022-04-27  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了ios – Swift:用NSOperation保留循环大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
在我的应用程序中,我使用图像加载器类从Web加载图像以获取集合视图.该类跟踪下载操作,并在集合视图中不再显示图像的单元格时取消它们.此实现基于NSOperation的Raywenderlich教程: http://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift.

使用NSOperation从网上下载图像.我注意到仪器公司没有发布任何NS操作.这会为下载的每个图像增加已用内存.在完成块中,我引用了“self”.所以我发现我创建了一个保留周期.

我在网上看了很多例子.我知道我可以使用“弱自我”或“无主自我”的捕获列表.我尝试了这个完成块,但仍然没有发布操作.

我的图像加载器类的代码如下:

import Foundation
import UIKit

class ImageLoader {
    lazy var downloadsInProgress = [NSIndexPath:NSOperation]()  
    lazy var downloadQueue:NSOperationQueue = {
        var queue = NSOperationQueue()
        queue.name = "Image Download queue"
        return queue
    }()

    let cache = NSCache()       // contains NSData objects for images

    init() {
        // Max. cache size is 10% of available physical memory (in MB's)
        cache.@R_372_10586@lCostLimit = 200 * 1024 * 1024    // TODO: change to 10%
    }

    /**
     * Download image based on url for given indexpath. 
     * The download is only started if the indexpath is still present in the downloadsInProgress array
     */

    func startDownloadForUrl(url: String,indexPath: NSIndexPath,completion: (imageData: NSData?) -> Void) {
        // check @R_675_9792@ownload request is already present
        @R_675_9792@ownloadsInProgress[indexPath] != nil {
            return
        }

        // check cache
        if let imageData = self.cache.objectForKey(url) as? NSData {
            NSOperationQueue.mainQueue().addoperationWithBlock() {
                //remove indexpath from progress queue
                self.downloadsInProgress.removeValueForKey(indexPath)
                completion(imageData: imageData)
            }
            return
        }

        // prepare the download
        let downloader = ImageDownloader(url: url)

        downloader.completionBlock = {
            [uNowned self] in

            @R_675_9792@ownloader.cancelled {
                return
            }

            // image is retrieved from web
            NSOperationQueue.mainQueue().addoperationWithBlock() {
                [uNowned self] in

                //remove indexpath from progress queue
                self.downloadsInProgress.removeValueForKey(indexPath)

                // add image to cache
                @R_675_9792@ownloader.imageData != nil {
                    self.cache.setObject(downloader.imageData!,forKey: url,cost: downloader.imageData!.length)
                }
                completion(imageData: downloader.imageData)
            }
        }

        // add downloader to operations in progress and start the operation
    NSOperationQueue.mainQueue().addoperationWithBlock() {
            [uNowned self] in

            self.downloadsInProgress[indexPath] = downloader
            self.downloadQueue.addoperation(downloader)
        }
    } 


    /**
     * Suspends queue for downloading images
     */

    func suspendAllOperations() {
        downloadQueue.suspended = true
    }


    /**
     * Resumes queue for downloading images
     */

    func resumeAllOperations() {
        downloadQueue.suspended = false
    }


    /**
     * Cancels downloads for NOT visible indexpaths. The parameter specifies an array of visible indexpaths!
     */

    func cancelDownloads(visibleIndexPaths: [NSIndexPath]) {
        let allPendingOperations = Set(downloadsInProgress.keys)
        let visiblePaths = Set(visibleIndexPaths)

        // cancel all pending operations for indexpaths that are not visible
        var toBeCancelled = allPendingOperations
        toBeCancelled.subtracTinPlace(visiblePaths)

        for indexPath in toBeCancelled {
            if let pendingDownloadoperation = downloadsInProgress[indexPath] {
                pendingDownloadoperation.cancel()
            }

            downloadsInProgress.removeValueForKey(indexPath)
        }
    }
}


class ImageDownloader: NSOperation {
    var url: String
    var imageData: NSData?

    init(url: String) {
        self.url = url
    }

    override func main() {
        if self.cancelled {
            return
        }

        if let imageUrl = NSURL(String: url) {
            // retrieve data from web
            setNetworkActivityInDicatorVisible(true)
            imageData = NSData(contentsOfURL: imageUrl)
            setNetworkActivityInDicatorVisible(false)

            if self.cancelled {
                imageData = nil
                return
            }

            // scale image
            if imageData != nil {
                if let image = UIImage(data: imageData!) {
                    let imageData2 = UIImageJPEGRepresentation(image,1.0)
                    let compressionRate = Float(imageData!.length) / Float(imageData2!.length)

                    let scaleWidth = 244 / image.size.width
                    let scaleHeight = 244 / image.size.height
                    let imageScale = min(scaleWidth,scaleHeight)

                    let rect = CGRectMake(0.0,0.0,image.size.width * imageScale,image.size.height * imageScalE)

                    UIGraphicsBeginImageContext(rect.sizE)
                    image.drawInRect(rect)
                    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
                    let scaledImageData = UIImageJPEGRepresentation(scaledImage,CGFloat(compressionRatE))
                    UIGraphicsEndImageContext()

                    imageData = scaledImageData
                }
            }
        }
    }

    private func setNetworkActivityInDicatorVisible(visible: Bool) {
        NSOperationQueue.mainQueue().addoperationWithBlock() {
            let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
            appDelegate.setNetworkActivityInDicatorVisible(visiblE)
        }
    }
}

我究竟在哪里创建保留周期?我该如何解决这个问题?
什么时候应该使用’无主’,什么时候应该使用’弱’?

如果有人能解释解决方案我会很感激,@R_640_9447@从错误中吸取教训.

解决方法

发现了这个问题.保留周期不是由引用self引起的,而是通过在NSOperation的完成块中引用NSOperation引起的!

函数startDownloadForUrl(…)中,我声明了变量下载器.接下来,我为此变量声明一个完成块.在这个完成块中,我引用了变量下载器.这导致保留周期.

我通过在完成块中使用[uNowned downloader]解决了这个问题.

这造成了另一个问题.在完成块中,我异步调用主线程.在此调用中,使用了变量downloader.imageData.由于此异步调用,NSOperation可能已经结束,并且变量下载器可能不再存在.为了避免崩溃,我为imageData声明了一个新变量,因此在主线程中使用时数据仍然可用.

完成块现在看起来像:

downloader.completionBlock = {
    [uNowned downloader] in
    @R_675_9792@ownloader.cancelled {
        return
    }

    let imageData = downloader.imageData    // retain the imageData. It will be used asynchrounous in the main thread. The downloader operation might already be finished and downloader will no longer exists.

    // image is retrieved from web
    NSOperationQueue.mainQueue().addoperationWithBlock() {
        //remove indexpath from progress queue
        self.downloadsInProgress.removeValueForKey(indexPath)

        // add image to cache
        if imageData != nil {
            self.cache.setObject(imageData!,cost: imageData!.length)
        }
        completion(imageData: imageData)
    }
}

大佬总结

以上是大佬教程为你收集整理的ios – Swift:用NSOperation保留循环全部内容,希望文章能够帮你解决ios – Swift:用NSOperation保留循环所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。