我收到了错误消息。它在DispatchQueue调用时返回nil。
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
事实证明,这是我遇到崩溃的地方。
headerImageView
只是一个未通过IBOutlet
连接到故事板的变量。这是整个代码:
import UIKit
import WebKit
let offset_HeaderStop:CGFloat = 40.0
let offset_B_LabelHeader:CGFloat = 95.0
let distance_W_LabelHeader:CGFloat = 35.0
class MovieDetailsViewController: UIViewController, UIScrollViewDelegate {
var movie: Movie?
var urlBuilder = MovieUrlBuilder()
var config = TMDBConfiguration()
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var headerView: UIView!
@IBOutlet weak var headerLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var genreLabel: UILabel!
@IBOutlet weak var ratingLabel: UILabel!
@IBOutlet weak var releaseLabel: UILabel!
@IBOutlet weak var descriptionText: UITextView!
@IBOutlet weak var trailerContainerView: UIView!
@IBOutlet weak var trailerLabel: UILabel!
@IBOutlet weak var videoContainer: WKWebView!
var headerImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
headerImageView = UIImageView(frame: headerView.bounds)
headerImageView.image = UIImage(named: "Poster")
headerImageView.contentMode = .scaleAspectFill
headerView.insertSubview(headerImageView, belowSubview: headerLabel)
headerView.clipsToBounds = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchPopularMovies()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
var headerTransform = CATransform3DIdentity
if offset < 0 {
let headerScaleFactor: CGFloat = -(offset) / headerView.bounds.height
let headerSizeVariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizeVariation, 0)
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
headerView.layer.transform = headerTransform
} else {
headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offset_HeaderStop, -offset), 0)
let labelTransform = CATransform3DMakeTranslation(0, max(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0)
headerLabel.layer.transform = labelTransform
}
headerView.layer.transform = headerTransform
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return UIStatusBarStyle.lightContent
}
private func fetchPopularMovies() {
if let poster = movie?.backdropPath {
let baseURL = URL(string: config.baseImageURL)!
let url = baseURL.appendingPathComponent("w500").appendingPathComponent(poster)
let request = URLRequest(url: url)
let task = urlBuilder.session.dataTask(with: request) {(data, response, error) in
do {
if let image = UIImage(data: data!) {
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
}
}
}
task.resume()
}
}
}
感谢您的支持!
答案 0 :(得分:0)
您的异步呼叫位于fetchPopularMovies
,viewWillAppear
呼叫。您在viewDidAppear
中初始化了图片视图,在 viewWillAppear
之后称为。
基本上,headerImageView
是零。
“但是我把电话放在了async
区块中!所以当我设置图像视图的图像时,应该已经调用了viewDidAppear
,对吧?”你说。
好吧,依靠async
说“我希望在某个方法返回后运行这个东西”不是一个好主意。并不总能保证这样做。
要解决此问题,您需要在调用 fetchPopularMovies
之前初始化标题图像视图。例如,您可以将其放在viewDidLoad
中。
答案 1 :(得分:0)
您正在初始化viewDidAppear
中的图片视图,该图片将在 viewWillAppear
之后被称为,其中填充了图片视图。尽管有异步任务,但不能保证在填充之前初始化视图。
我建议懒洋洋地初始化图片视图,好处是该属性是非可选的,并且在第一次访问时会初始化一次。
lazy var headerImageView: UIImageView = {
let view = UIImageView(frame: self.headerView.bounds)
view.image = UIImage(named: "Poster")
view.contentMode = .scaleAspectFill
self.headerView.insertSubview(view, belowSubview: self.headerLabel)
view.clipsToBounds = true
return view
}()