我试图测量将一张大照片(JPEG)从文件加载到UIImageView上的iOS 8.0所需的时间。
我现在的代码是:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBAction func loadImage(sender: UIButton) {
if let imageFile = NSBundle.mainBundle().pathForResource("large_photo", ofType: "jpg") {
// start our timer
let tick = Tick()
// loads a very large image file into imageView
// the test photo used is a 4608 × 3456 pixel JPEG
// using contentsOfFile: to prevent caching while testing timer
imageView.image = UIImage(contentsOfFile: imageFile)
// stop our timer and print execution time
tick.tock()
}
}
}
class Tick {
let tickTime : NSDate
init () {
tickTime = NSDate()
}
func tock () {
let tockTime = NSDate()
let executionTime = tockTime.timeIntervalSinceDate(tickTime)
println("[execution time]: \(executionTime)")
}
}当我在我的测试设备(第5代iPod触摸)上加载一个非常大的图像(4608x3456JPEG)时,我可以看到执行时间是2-3秒,并阻塞主线程。这可以通过这样一个事实观察到:在这段时间内,UIButton仍然处于突出显示的状态,并且其他UI元素不允许交互。
因此,我希望我的计时函数报告的时间为2-3秒.然而,它报告的时间是毫秒--例如:
[execution time]: 0.0116159915924072此tick.tock()在加载图像之前将消息打印到控制台。这让我感到困惑,因为主线程出现阻塞,直到加载图像之后。
这使我提出以下问题:
tick.tock()函数会在图像显示之前打印到控制台?发布于 2015-05-13 21:11:31
你在这里测量的东西有两部分:
从磁盘加载映像:
UIImage(contentsOfFile: imageFile)
并将图像从JPEG解压缩到要显示的位图:
imageView.image = ....
第一部分涉及从磁盘(磁盘I/O)实际检索压缩的JPEG数据,并创建一个UIImage对象。UIImage对象保存对压缩数据的引用,直到需要显示。只有在它准备被呈现到屏幕的时刻,它才会将图像解压缩成一个位图来显示(在主线程上)。
我的猜测是,您的计时器只捕获磁盘加载部分,解压缩在下一个运行循环中进行。那么大的图像的解压可能需要一段时间,可能是狮子共享的时间。
如果要显式地度量解压缩所需的时间,则需要手动完成,方法是将图像绘制到屏幕外的上下文中,如下所示:
let tick = Tick()
// Load the image from disk
let image = UIImage(contentsOfFile: imageFile)
// Decompress the image into a bitmap
var newImage:UIImage;
UIGraphicsBeginImageContextWithOptions(image.size, true, 0);
image.drawInRect(CGRect(x:0,y:0,width:image.size.width, height:image.size.height))
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
tick.tock()在这里,我们正在复制将image分配给imageView.image时发生的解压缩。
在处理这种大小的图像时,保持UI响应性的一个方便的技巧是将整个进程踢到后台线程上。这很好,因为一旦您手动解压缩了映像,UIKit就会检测到这一点,并且不会重复这个过程。
// Switch to background thread
dispatch_async(dispatch_get_global_queue(Int(DISPATCH_QUEUE_PRIORITY_DEFAULT.value), 0)) {
// Load the image from disk
let image = UIImage(contentsOfFile: imageFile)
// Ref to the decompressed image
var newImage:UIImage;
// Decompress the image into a bitmap
UIGraphicsBeginImageContextWithOptions(image.size, true, 0);
image.drawInRect(CGRect(x:0,y:0,width:image.size.width, height:image.size.height))
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Switch back to main thread
dispatch_async(dispatch_get_main_queue()) {
// Display the decompressed image
imageView.image = newImage
}
}免责声明:这里的代码还没有在Xcode中进行全面测试,但是如果您决定使用它,那么它是99%正确的。
发布于 2015-05-12 16:22:03
我会尝试使用单元测试来计时,因为XCTest框架提供了一些很好的性能度量工具。我认为这种方法可以解决懒惰的装载问题.虽然我不是百分之百的。
func testImagePerformance() {
let date = NSDate()
measureBlock() {
if let imageFile = NSBundle.mainBundle().pathForResource("large_photo", ofType: "jpg") {
imageView.image = UIImage(contentsOfFile: imageFile)
}
}
}(顺便提一下,你提到的加载阻塞了主应用程序线程.你应该用NSOperationQueue来确保这不会发生.你可能已经知道了:http://nshipster.com/nsoperation/)
https://stackoverflow.com/questions/30194395
复制相似问题