swift - 关闭 UIViewController 后 UI 卡住 5 秒

标签 swift uiviewcontroller uicollectionview

我有一个图像的 UICollectionView 和一个在选择任何图像时打开的完整 ImageView 。 打开完整图像效果很好,但一旦我关闭它,整个应用程序就会卡住超过 5 秒。我读到主线程可能过载,这可以解释延迟,但我不确定要移动到哪些线程以及移动到哪里,如果这是问题的话。

import UIKit

class FullImageViewController: UIViewController , UIScrollViewDelegate {

    var scroller: UIScrollView!
    var width = CGFloat()
    var images = [Image]()
    var imageArray = [UIImage]()
    var imgs: [UIImage] = [UIImage(named: "pug7")!, UIImage(named: "pug6")!, UIImage(named: "pug7")!, UIImage(named: "pug6")!]
    var index = Int()
    var fullImagesAdded = Bool()

    init(width: CGFloat, images: [Image], index: Int, imageArray: [UIImage]) {

        super.init(nibName: nil, bundle: nil)
        self.width = width
        self.images = images
        self.index = index
        self.imageArray = imageArray
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(FullImageViewController.swipeDown))
        downSwipe.direction = .Down
        view.addGestureRecognizer(downSwipe)

        self.scroller = UIScrollView()
        self.scroller.delegate = self
        var i = 0
        for img in images {
            let aimageDetailViewController = ImageDetailViewController(index: self.index, image: img)
            self.scroller.addSubview(aimageDetailViewController.view)
            var aimageDetailViewFrame: CGRect = aimageDetailViewController.view.frame
            aimageDetailViewFrame.origin.x = (super.view.frame.width) * CGFloat(i)
            aimageDetailViewController.view.frame = aimageDetailViewFrame

            i += 1
        }

        self.scroller.backgroundColor = UIColor.blackColor()
        self.scroller.contentSize = CGSizeMake(self.view.frame.width * CGFloat(images.count), self.view.frame.height)
        self.scroller.bounces = false
        self.scroller.showsHorizontalScrollIndicator = false
        self.scroller.setContentOffset(CGPoint(x: self.view.frame.width * CGFloat(index), y: 0), animated: false)
        self.scroller.pagingEnabled = true

        self.view.addSubview(scroller)
    }

    func swipeDown(){
        dispatch_async(dispatch_get_main_queue()) {
            self.dismissViewControllerAnimated(true, completion: nil)
        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        scroller.frame = view.bounds
    }
}

这是我在 UICollectionView 中调用完整 ImageView 的地方:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    let fullImage = FullImageViewController(width: CGFloat(imageURLSCache.count), images: imageURLSCache, index: Int(indexPath.row), imageArray: images)
    self.presentViewController(fullImage, animated: true, completion: nil)
}

谢谢!

这是我用来下载完整 ImageView 和 Collection View 的图像的扩展

extension UIImageView {

func downloadFrom(link link:String?, cache: NSCache ) {
    image = UIImage(named: "logo")
    self.alpha = 0.3
    let data: NSData? = cache.objectForKey(link!) as? NSData


    if let cachedData = data {
        let image = UIImage(data: cachedData)
        dispatch_async(dispatch_get_main_queue(), {() in
            self.image = image
            self.alpha = 1
            images.append(self.image!)
        })
        return
    }


    if link != nil, let url = NSURL(string: link!) {
        NSURLSession.sharedSession().dataTaskWithURL(url) { data, response, error in
            guard let data = data where error == nil else {
                print("\nerror on download \(error)")
                return
            }
            if let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode != 200 {
                print("statusCode != 200; \(httpResponse.statusCode)")
                return
            }
            dispatch_async(dispatch_get_main_queue()) {
                print("\ndownload completed \(url.lastPathComponent!)")
                self.image = UIImage(data: data)
                self.alpha = 1
                cache.setObject(data, forKey: link!)
            }
            }.resume()
    } else {
        dispatch_async(dispatch_get_main_queue(), {
            self.image = UIImage(named: "logo")
        })

    }
}

}

最佳答案

func swipeDown(){
    dispatch_async(dispatch_get_main_queue()) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}

此方法已设置为 UISwipeGestureRecognizer 的操作。它将由手势识别器在主线程上调用,因此您不需要将其分派(dispatch)到主队列。这会增加延迟,具体取决于队列的繁忙程度。

将其更改为:

func swipeDown() {
    self.dismissViewControllerAnimated(true, completion: nil)
}

有关您添加的附加信息的更新:

UIImageView 上的扩展不是很好(即,当使用它作为缓存的键时,它假设 link 不是 nil ,但稍后检查它是否为 nil,但不可能是这样,否则你已经崩溃了)。但它至少使用 dataTaskWithURL 方法在后台进行下载。

我会尝试在调度到后台调用中调用它,如下所示,以确保您不会因缓存检查等而使主线程重载。我假设您正在安全地为此扩展创建缓存,并且当然会重用所有调用的缓存,而不是为每个调用创建一个新的缓存(我已经看到这样做了)。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
    imageView.downloadFrom(....)
}

这是一个可供使用的替代扩展。这是我经常使用的一个。它会为您创建缓存,因此您不必担心在扩展之外执行此操作。它还具有确认自图像开始下载以来尚未在图像上设置另一个 URL 的好处。例如,当 ImageView 位于可重复使用的单元上时,这一点很重要。创建单元格,将图像 url 设置为 x,当它仍在下载时,单元格滚动到屏幕外并重新使用,图像 url 设置为 y,然后 x 下载完成并显示适用于旧单元格的图像。

代码如下:

//  UIImageView+XCGAdditions.swift
//  Cerebral Gardens
//
//  Created by Dave Wood
//  Copyright © Cerebral Gardens. All rights reserved.

import UIKit

extension UIImageView {

    func setImageWithLink(link: String) {
        guard let url = NSURL(string: link) else { return }
        setImageWithURL(url: url)
    }

    func setImageWithURL(url url: NSURL) {
        let checkInt = Int(arc4random_uniform(100000))
        tag = checkInt

        struct Statics {
            static var onceToken: dispatch_once_t = 0
            static var imageCache: NSCache!
        }
        dispatch_once(&Statics.onceToken) { () -> Void in
            Statics.imageCache = NSCache()
        }

        if let cachedImage = Statics.imageCache.objectForKey(url) as? UIImage {
            self.image = cachedImage
            return
        }

        NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> () in
            guard let data = data where error == nil,
              let image = UIImage(data: data) where self.tag == checkInt else { return }

            dispatch_async(dispatch_get_main_queue()) { () -> () in
                Statics.imageCache.setObject(image, forKey: url)
                self.image = image
            }
        }).resume()
    }
}

关于swift - 关闭 UIViewController 后 UI 卡住 5 秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36815317/

相关文章:

swift - 如果冗余代码,Swift 有什么优势吗?

swift : My files in Firebase Storage wouldn't be deleted

ios - 在dismissViewControllerAnimated 之后的presentViewController

ios - tableviewcell 不会横向拉伸(stretch),即方向改变

ios - 在移动应用程序上创建新闻提要的 UICollectionView 代码

ios - UICollectionViewCell 在 sizeForItemAt 中不可用

ios - 如何使用一键添加不同整数的分数(swift3)

swift - CoreData 与 Swift

swift - 将 alpha 设置回 1.0 后,不会重新出现任何按钮/标签/任何内容

ios - 流行 Segue 后方向未更新