我使用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保留循环所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)