我有一个带有UIImageView的collectionViewHeader,设置为具有灰色backgroundColor。有一个addPhotoButton,它将用户带到另一个Controller。当他们选择图像时,它会返回到原始控制器,并且应该是UIImageView中的图像。
这是collectionViewHeader中的代码:
var selectedImage: UIImage? {
didSet {
self.imageView.image = selectedImage!
print("This is the selectedImage:", selectedImage!)
}
}
let imageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = UIColor.rgb(red: 234, green: 246, blue: 246)
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
这是我遇到的每个教程或StackOverflow帖子都说要做的。和打印语句:
print("This is the selectedImage:", selectedImage!)
正在打印:
This is the selectedImage: <UIImage: 0x600001000380>, {485, 482}
所以图像在那里,但是没有放在UIImageView中。
imageView将被添加到子视图中并锚定以在标题的init中设置大小:
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(imageView)
addSubview(addimageButton)
addSubview(addimageText)
if #available(iOS 11.0, *){
eventImageView.anchor(top: safeAreaLayoutGuide.topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: frame.width, height: 175)
} else {
// Fallback on earlier OS?
}
addimageButton.anchor(top: eventImageView.topAnchor, left: eventImageView.leftAnchor, bottom: nil, right: imageView.rightAnchor, paddingTop: 25, paddingLeft: (imageView.bounds.size.width - addimageButton.bounds.size.width) / 2, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
addimageText.anchor(top: nil, left: imageView.leftAnchor, bottom: imageView.bottomAnchor, right: imageView.rightAnchor, paddingTop: 0, paddingLeft: (imageView.bounds.size.width - addimageButton.bounds.size.width) / 2, paddingBottom: 25, paddingRight: 0, width: 0, height: 0)
}
selectedImage
是在此处另一个控制器的标题中设置的:
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerId, for: indexPath) as! PhotoSelectorHeader
self.header = header
header.photoImageView.image = selectedImage
if let selectedImage = selectedImage {
if let index = self.images.index(of: selectedImage) {
let selectedAsset = self.assets[index]
let imageManager = PHImageManager.default()
let targetSize = CGSize(width: 600, height: 600)
imageManager.requestImage(for: selectedAsset, targetSize: targetSize, contentMode: .default, options: nil, resultHandler: { (image, info) in
header.photoImageView.image = image
})
}
}
return header
}
fileprivate func setupNavigationButtons() {
navigationController?.navigationBar.tintColor = .black
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(handleCancel))
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Select", style: .plain, target: self, action: #selector(handleNext))
}
@objc func handleNext() {
let addPhotoHeader = AddPhotoHeader()
addPhotoHeader.selectedImage = header?.photoImageView.image
navigationController?.popViewController(animated: true)
}
我确定这里缺少一个快速步骤,但是我已经被困了几天了!
如果您认为问题可能在我的项目中的其他地方,请告诉我。
提前感谢您的帮助!
答案 0 :(得分:0)
两个问题:
您不会在主线程上调用此命令(如果从主线程进行设置,则可以起作用,但是我会假设它不是,因为UIImageView是“请适当更新。
(可选的修复程序),您正在通过强制投射可选的selectedImage
来请求崩溃。
var selectedImage: UIImage? {
didSet {
DispatchQueue.main.async { [weak self] in
// Don't force-cast (!) the optional selectedImage.
// Since you can assign a nil image to self?.imageView.image, do that instead
// Other option is adding a guard-statement here:
// guard selectedImage != nil else { return }
self?.imageView.image = selectedImage
print("This is the selectedImage:", selectedImage)
}
}
}
每当设置了与UI相关的内容但未在视觉上进行更新,而其他一切看起来都很好时,很有可能跳转到主线程将起作用。主线程保留用于所有用户界面更改,例如更新图像,刷新表视图或弄乱约束。
几乎所有包含UI
(UIImageView
)的对象都只需要在主线程上进行更新。可能出现的问题范围从UI对象更新的严重延迟到崩溃。
但是,任何长时间运行的任务或繁重的过程(例如网络请求或处理像素级别的图片)应该不在主线程上运行,否则您的用户界面将在该过程结束时停止。
@twostraws(Twitter)很好地在这里解释了主线程:https://www.hackingwithswift.com/read/9/4/back-to-the-main-thread-dispatchqueuemain
他提到了这一点,但我完全同意:
这一点非常重要,需要重复两次:在后台线程上执行用户界面工作永远都不行。
希望这会有所帮助!