Swift 低分辨率图像加载时间过长
使用Facebook Graph API,我检索到了一个指向Swift 低分辨率图像加载时间过长,swift,nsurlsession,dispatch-async,Swift,Nsurlsession,Dispatch Async,使用Facebook Graph API,我检索到了一个指向200x200个人资料图片的字符串URL,该图片要显示在UIImageView中。我成功地做到了这一点,但我注意到,图像显示在屏幕上可能需要长达10秒的时间。有谁能给我一些关于如何优化它的建议(没有双关语的意思) override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) NSURLSession.sharedSession()
200x200
个人资料图片的字符串URL,该图片要显示在UIImageView
中。我成功地做到了这一点,但我注意到,图像显示在屏幕上可能需要长达10秒的时间。有谁能给我一些关于如何优化它的建议(没有双关语的意思)
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) ->
Void in
self.profilePictureImageView.image = UIImage(data: data!)
self.profilePictureImageView.layer.cornerRadius = self.profilePictureImageView.frame.size.width / 2;
self.profilePictureImageView.clipsToBounds = true
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.view.addSubview(self.profilePictureImageView)
})
}).resume()
}
您应该将所有
UIView
调用(因此您在UIImageView
上设置的任何内容)移动到主线程上,因为UIKit在大多数情况下都不是线程安全的。您可以在后台线程上实例化UIImage
,以优化性能,因此请尝试以下操作:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let url = NSURL(string: self.profilePictureUrl)!
NSURLSession.sharedSession().dataTaskWithURL(
url,
completionHandler: { [weak self] (data, response, error) -> Void in
guard let strongSelf = self else { return }
// create the UIImage on the background thread
let image = UIImage(data: data!)
// then jump to the main thread to modify your UIImageView
dispatch_async(dispatch_get_main_queue(), { [weak self] () -> Void in
guard let strongSelf = self else { return }
let profilePictureImageView = strongSelf.profilePictureImageView
profilePictureImageView.image = image
profilePictureImageView.layer.cornerRadius = profilePictureImageView.frame.size.width / 2;
profilePictureImageView.clipsToBounds = true
strongSelf.view.addSubview(profilePictureImageView)
})
}
).resume()
}
还请注意,我已将您对
self
的引用弱化了。无法保证用户在调用完成例程时没有解除启动此代码的视图控制器,因此您希望确保没有保留对self
的强引用。这允许视图控制器在用户解除它时解除分配,然后完成例程提前返回,而不做任何不必要的工作。您应该将所有UIView
调用(因此您在UIImageView
上设置的任何内容)移动到主线程上,因为大部分情况下UIKit都不是线程安全的。您可以在后台线程上实例化UIImage
,以优化性能,因此请尝试以下操作:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let url = NSURL(string: self.profilePictureUrl)!
NSURLSession.sharedSession().dataTaskWithURL(
url,
completionHandler: { [weak self] (data, response, error) -> Void in
guard let strongSelf = self else { return }
// create the UIImage on the background thread
let image = UIImage(data: data!)
// then jump to the main thread to modify your UIImageView
dispatch_async(dispatch_get_main_queue(), { [weak self] () -> Void in
guard let strongSelf = self else { return }
let profilePictureImageView = strongSelf.profilePictureImageView
profilePictureImageView.image = image
profilePictureImageView.layer.cornerRadius = profilePictureImageView.frame.size.width / 2;
profilePictureImageView.clipsToBounds = true
strongSelf.view.addSubview(profilePictureImageView)
})
}
).resume()
}
还请注意,我已将您对self
的引用弱化了。无法保证用户在调用完成例程时没有解除启动此代码的视图控制器,因此您希望确保没有保留对self
的强引用。如果用户解除了视图控制器,并且完成例程提前返回而不做任何不必要的工作,则允许视图控制器解除分配。此代码是非法的:
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) ->
Void in
self.profilePictureImageView.image = UIImage(data: data!)
住手!您正在背景线程上设置UIImageView的图像。不,UIKit不是线程安全的。您必须进入主线程才能执行此操作。(您最终会进入代码中的主线程,但为时已晚。)此代码是非法的:
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) ->
Void in
self.profilePictureImageView.image = UIImage(data: data!)
住手!您正在背景线程上设置UIImageView的图像。不,UIKit不是线程安全的。您必须进入主线程才能执行此操作。(您最终会进入代码中的主线程,但这样做太晚了。)可能尝试在异步调用之外添加子视图,然后在完成块中设置子视图的映像?可能尝试在异步调用之外添加子视图,然后在完成块中设置子视图的图像?非常感谢所有这些改进。我很好奇-您是否有意创建了两个对strongSelf
的引用?我之所以问这个问题,是因为Xcode对其中一个声明给出了警告。是的,您需要两个对strongSelf
的引用,因为每个回调都可能跳转一个线程。如果Xcode抱怨,您将不得不更改其中一个变量名,例如,使用内部变量名strongSelfInner
。非常感谢您所做的所有改进。我很好奇-您是否有意创建了两个对strongSelf
的引用?我之所以问这个问题,是因为Xcode对其中一个声明给出了警告。是的,您需要两个对strongSelf
的引用,因为每个回调都可能跳转一个线程。如果Xcode抱怨您必须更改其中一个变量名,例如,使用内部变量名strongSelfInner
。