ios – Swift:用NSOperation保留循环

ios – Swift:用NSOperation保留循环,第1张

概述在我的应用程序中,我使用图像加载器类从Web加载图像以获取集合视图.该类跟踪下载 *** 作,并在集合视图中不再显示图像的单元格时取消它们.此实现基于NSOperation的Raywenderlich教程: http://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift. 我使用NSOperation从网上下载图像.我注意 在我的应用程序中,我使用图像加载器类从Web加载图像以获取集合视图.该类跟踪下载 *** 作,并在集合视图中不再显示图像的单元格时取消它们.此实现基于NSOperation的Raywenderlich教程: http://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift.

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

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

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

import Foundationimport UIKitclass 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.totalCostlimit = 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 if download request is already present        if downloadsInProgress[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            if downloader.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                if downloader.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)        }    }}

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

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

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

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

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

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

完成块现在看起来像:

downloader.completionBlock = {    [uNowned downloader] in    if downloader.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保留循环所遇到的程序开发问题。

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1028552.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存