When I cancel the "touchTapped" and "assignTap" methods, the "photoImageView.image", "rawImage" change according to the collectionView cell image but the problem is the collectionView images start changing too. If I keep the methods and add "collectionView.reloadData()" after the 76th line, the "photoImageView.image", "rawImage" don't change.I think I need to implement a different logic for;var rawImage: UIImage? { get { photoImageView.image } set { photoImageView.image = newValue } }
Post
Replies
Boosts
Views
Activity
I feel like I'm getting close. Any feedback please ?import Foundation
import UIKit
import Photos
class PhotoViewController: UIViewController {
@IBOutlet weak var photoImageView: UIImageView!
@IBOutlet var photoView: UIView!
@IBOutlet weak var menuStackView: UIStackView!
var imagePicker = UIImagePickerController()
var effects = Effects()
var rawImage: UIImage? {
get {
photoImageView.image
}
set {
photoImageView.image = newValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
assignTap()
view.addSubview(collectionView)
collectionView.backgroundColor = .white
collectionView.topAnchor.constraint(equalTo: photoImageView.bottomAnchor, constant: 110).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 10).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -103).isActive = true
collectionView.clipsToBounds = true
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isHidden = false
}
@IBAction func previewTapped(_ sender: UIButton) {
sender.pulsate()
if collectionView.isHidden == true {
collectionView.isHidden = false
} else {
collectionView.isHidden = true
}
}
@IBAction func effectsTapped(_ sender: UIButton) {
sender.flash()
}
@IBAction func exportTapped(_ sender: UIButton) {
sender.shake()
}
func assignTap() {
let tap = UITapGestureRecognizer(target: self, action: #selector(touchTapped(_:)))
photoView.addGestureRecognizer(tap)
}
@objc func touchTapped(_ sender: UITapGestureRecognizer) {
if collectionView.isTracking == false {
if menuStackView.isHidden == false {
collectionView.isHidden = true
menuStackView.isHidden = true
} else {
menuStackView.isHidden = false
collectionView.isHidden = false
}
}
}
func chooseImage(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker,animated: true, completion: nil)
}
}
func accessVideo(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePicker.sourceType = .camera
self.present(imagePicker, animated: true, completion: nil)
} else {
print("Camera not available")
}
}
public func chooseLastImage(_ sender: Any) {
print("photoImageView", photoImageView!)
print("photoImageView.bounds", photoImageView.bounds)
let targetSize: CGSize? = CGSize(width: photoImageView.bounds.width, height: photoImageView.bounds.height)
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = true
options.deliveryMode = .highQualityFormat
let imgManager = PHImageManager.default()
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)]
let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
print("targetSize for request", targetSize!)
imgManager.requestImage(for: fetchResult.lastObject!, targetSize: targetSize!, contentMode: .default, options: options) { (result, info) in
guard let result = result else { return }
DispatchQueue.main.async(execute: {
self.rawImage = result
self.collectionView.reloadData()
})
}
}
fileprivate let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(CustomCell.self, forCellWithReuseIdentifier: "PreviewCell")
return cv
}()
}
extension PhotoViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width/5, height: collectionView.frame.width/4)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 11
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PreviewCell", for: indexPath) as! CustomCell
cell.bgImage = photoImageView.image
if indexPath.row == 0 {
cell.labelText = "A"
}
if indexPath.row == 1 {
cell.labelText = "B"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectChrome", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 2 {
cell.labelText = "C"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectInstant", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 3 {
cell.labelText = "D"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectNoir", filterEffectValue: nil, filterEffectValueName: kCIInputImageKey))
}
if indexPath.row == 4 {
cell.labelText = "E"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectMono", filterEffectValue: nil, filterEffectValueName: kCIInputImageKey))
}
if indexPath.row == 5 {
cell.labelText = "F"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIExposureAdjust", filterEffectValue: 1, filterEffectValueName: kCIInputEVKey))
}
if indexPath.row == 6 {
cell.labelText = "G"
guard cell.bgImage != nil else {
return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CISRGBToneCurveToLinear", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 7 {
cell.labelText = "H"
guard cell.bgImage != nil else { return cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectTransfer", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 8 {
cell.labelText = "I"
guard cell.bgImage != nil else { return
cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIColorPosterize", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 9 {
cell.labelText = "J"
guard cell.bgImage != nil else { return
cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectProcess", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 10 {
cell.labelText = "K"
guard cell.bgImage != nil else { return
cell
}
cell.bgImage = effects.applyFilterTo(image: photoImageView.image!, filterEffect: Effects.Filter(filterName: "CIVignetteEffect", filterEffectValue: nil, filterEffectValueName: nil))
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 5, bottom: 10, right: 5)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 {
rawImage = photoImageView.image
}
if indexPath.row == 1 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectChrome", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 2 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectInstant", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 3 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectNoir", filterEffectValue: nil, filterEffectValueName: kCIInputImageKey))
}
if indexPath.row == 4 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectMono", filterEffectValue: nil, filterEffectValueName: kCIInputImageKey))
}
if indexPath.row == 5 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIExposureAdjust", filterEffectValue: 1, filterEffectValueName: kCIInputEVKey))
}
if indexPath.row == 6 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CISRGBToneCurveToLinear", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 7 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectTransfer", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 8 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIColorPosterize", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 9 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIPhotoEffectProcess", filterEffectValue: nil, filterEffectValueName: nil))
}
if indexPath.row == 10 {
rawImage = effects.applyFilterTo(image: rawImage!, filterEffect: Effects.Filter(filterName: "CIVignetteEffect", filterEffectValue: nil, filterEffectValueName: nil))
}
}
}
class CustomCell: UICollectionViewCell {
fileprivate let bg: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
return iv
}()
var bgImage: UIImage? {
get {
bg.image
}
set {
bg.image = newValue
}
}
fileprivate let label: UILabel = {
let il = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
il.translatesAutoresizingMaskIntoConstraints = false
il.contentMode = .scaleAspectFit
il.clipsToBounds = true
return il
}()
var labelText: String? {
get {
label.text
}
set {
label.text = newValue
}
}
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(bg)
contentView.addSubview(label)
bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension PhotoViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
photoImageView.image = image
}
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
Regarding line 151, I thought it would improve the UI performance. If it's not necessary, I will delete it.
Update: Not getting an error code anymore but the footer appears as the last item in the collectionView( as the 12th item in the collectionView), what could be the cause of that ?
import Foundationimport UIKitimport Photosclass PhotoViewController: UIViewController { @IBOutlet weak var photoImageView: UIImageView! @IBOutlet var photoView: UIView! @IBOutlet weak var menuStackView: UIStackView! var imagePicker = UIImagePickerController() override func viewDidLoad() { super.viewDidLoad() imagePicker.delegate = self assignTap() view.addSubview(collectionView) collectionView.backgroundColor = .white collectionView.topAnchor.constraint(equalTo: photoImageView.bottomAnchor, constant: 110).isActive = true collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 10).isActive = true collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -103).isActive = true collectionView.clipsToBounds = true collectionView.dataSource = self collectionView.delegate = self collectionView.isHidden = false } @IBAction func previewTapped(_ sender: UIButton) { sender.pulsate() if collectionView.isHidden == true { collectionView.isHidden = false } else { collectionView.isHidden = true } } @IBAction func effectsTapped(_ sender: UIButton) { sender.flash() } @IBAction func exportTapped(_ sender: UIButton) { sender.shake() } func assignTap() { let tap = UITapGestureRecognizer(target: self, action: #selector(touchTapped(_:))) photoView.addGestureRecognizer(tap) } @objc func touchTapped(_ sender: UITapGestureRecognizer) { if menuStackView.isHidden == false { collectionView.isHidden = true menuStackView.isHidden = true } else { menuStackView.isHidden = false collectionView.isHidden = false } } func chooseImage(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { imagePicker.sourceType = .photoLibrary imagePicker.allowsEditing = true self.present(imagePicker,animated: true, completion: nil) } } func accessVideo(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.camera) { imagePicker.sourceType = .camera self.present(imagePicker, animated: true, completion: nil) } else { print("Camera not available") } } public func chooseLastImage(_ sender: Any) { print("photoImageView", photoImageView!) print("photoImageView.bounds", photoImageView.bounds) let targetSize: CGSize? = CGSize(width: photoImageView.bounds.width, height: photoImageView.bounds.height) let options = PHImageRequestOptions() options.isNetworkAccessAllowed = true options.deliveryMode = .highQualityFormat let imgManager = PHImageManager.default() let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) print("targetSize for request", targetSize!) //What is its value imgManager.requestImage(for: fetchResult.lastObject!, targetSize: targetSize!, contentMode: .default, options: options) { (result, info) in guard let result = result else { return } DispatchQueue.main.async(execute: { self.photoImageView.image = result self.collectionView.reloadData() }) } } fileprivate let collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) cv.translatesAutoresizingMaskIntoConstraints = false cv.register(CustomCell.self, forCellWithReuseIdentifier: "PreviewCell") cv.register(CustomCell.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "FooterCell") return cv }()}extension PhotoViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.frame.width/5, height: collectionView.frame.width/4) } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == UICollectionView.elementKindSectionFooter { let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FooterCell", for: indexPath) as! CustomCell footer.backgroundColor = .blue return footer } else { assert(false, "Unexpected element kind") } } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 11 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PreviewCell", for: indexPath) as! CustomCell DispatchQueue.main.async { cell.bgImage = self.photoImageView.image } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 10, left: 5, bottom: 10, right: 5) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 1 } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: view.frame.width, height: 10) }}class CustomCell: UICollectionViewCell { fileprivate let bg: UIImageView = { let iv = UIImageView() iv.translatesAutoresizingMaskIntoConstraints = false iv.contentMode = .scaleAspectFit iv.clipsToBounds = true return iv }() var bgImage: UIImage? { get { bg.image } set { bg.image = newValue } } override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(bg) bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true }required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }}extension PhotoViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { photoImageView.image = image } dismiss(animated: true, completion: nil) } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { dismiss(animated: true, completion: nil) }}
Thank you for your reply. Because, I have created the collectionView programmatically, I don't have a representation of it on the storyboard. Would you like me to send you the whole code ?
Sorry for sending unindented. I tried "collectionView.reloadData()" in viewDidLoad(). Obviously, I was wrong. Thank you very much for your help.
Amazing, thank you so much. God bless!
I get the following error "Instance member 'photoViewController' cannot be used on type 'CustomCell'"class CustomCell: UICollectionViewCell { var photoViewController: PhotoViewController? fileprivate let bg: UIImageView = { let iv = UIImageView(image: photoViewController?.photoImageView.image) iv.translatesAutoresizingMaskIntoConstraints = false iv.contentMode = .scaleAspectFill iv.clipsToBounds = true return iv }()
I first set "cell.backgroundColor = .red" to be able to see the cells imageView working and yes I was seeing 11 red cells drawn. I removed that line to load the same image of "photoImageView". The issue I'm having is I just can't figure out how to set it up on line 108, iv.image = ?
I would like to have the same picture on the photoImageView and my collectionView imageView cells. The photoImageView receives its photo from the "chooseLastImage" func. When I migrate the "chooseLastImage" func into the CustomCell, I'm having problems with its parameter(_ sender: Any). I think it's impossible to access the picture from the photoImageView outlet.
Now, I get an empty collectionView. I guess the only way to make this work is;class CustomCell: UICollectionViewCell { var photoViewController: PhotoViewController? fileprivate let bg: UIImageView = { let iv = UIImageView() iv.image = ? iv.translatesAutoresizingMaskIntoConstraints = false iv.contentMode = .scaleAspectFill iv.clipsToBounds = true return iv }()My new code;import Foundationimport UIKitimport Photosclass PhotoViewController: UIViewController { @IBOutlet weak var photoImageView: UIImageView! @IBOutlet weak var peeTabBar: UITabBar! @IBOutlet var photoView: UIView! var imagePicker = UIImagePickerController() override func viewDidLoad() { super.viewDidLoad() imagePicker.delegate = self assignTap() view.addSubview(collectionView) collectionView.backgroundColor = .white collectionView.topAnchor.constraint(equalTo: photoImageView.bottomAnchor, constant: 110).isActive = true collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true collectionView.bottomAnchor.constraint(equalTo: peeTabBar.topAnchor, constant: -20).isActive = true collectionView.delegate = self collectionView.dataSource = self } func assignTap() { let tap = UITapGestureRecognizer(target: self, action: #selector(touchTapped(_:))) photoView.addGestureRecognizer(tap) } @objc func touchTapped(_ sender: UITapGestureRecognizer) { peeTabBar.isHidden = !peeTabBar.isHidden } func chooseImage(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { imagePicker.sourceType = .photoLibrary imagePicker.allowsEditing = true self.present(imagePicker,animated: true, completion: nil) } } func accessVideo(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.camera) { imagePicker.sourceType = .camera self.present(imagePicker, animated: true, completion: nil) } else { print("Camera not available") } } public func chooseLastImage(_ sender: Any) { print("photoImageView", photoImageView!) print("photoImageView.bounds", photoImageView.bounds) let targetSize: CGSize? = CGSize(width: photoImageView.bounds.width, height: photoImageView.bounds.height) let options = PHImageRequestOptions() options.isNetworkAccessAllowed = true options.deliveryMode = .highQualityFormat let imgManager = PHImageManager.default() let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) print("targetSize for request", targetSize!) //What is its value imgManager.requestImage(for: fetchResult.lastObject!, targetSize: targetSize!, contentMode: .default, options: options) { (result, info) in guard let result = result else { return } DispatchQueue.main.async(execute: { self.photoImageView.image = result }) } } fileprivate let collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) cv.translatesAutoresizingMaskIntoConstraints = false cv.register(CustomCell.self, forCellWithReuseIdentifier: "PreviewCell") return cv }()}extension PhotoViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.frame.width/5, height: collectionView.frame.width/5) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 11 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PreviewCell", for: indexPath) as! CustomCell cell.photoViewController = self return cell }}class CustomCell: UICollectionViewCell { var photoViewController: PhotoViewController? fileprivate let bg: UIImageView = { let iv = UIImageView() iv.translatesAutoresizingMaskIntoConstraints = false iv.contentMode = .scaleAspectFill iv.clipsToBounds = true return iv }() override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(bg) bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }}extension PhotoViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { photoImageView.image = image } dismiss(animated: true, completion: nil) } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { dismiss(animated: true, completion: nil) }}
Thank you so much for your effort, it really helped me alot on my project.
I've taken the steps you have suggested, the same error continues on the same line. The viewController calling the function;import Foundationimport UIKitimport Photosclass PhotoPopUpViewController: UIViewController { let photoViewController = PhotoViewController() override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { dismiss(animated: true, completion: nil) } @IBOutlet private var photoCollectionView: UICollectionView! @IBOutlet weak var tableView: UITableView! var imageArray = [UIImage]() var tableImages: [PhotoPopUpCellData] = [] var selectedTableImage: PhotoPopUpCellData? override func viewDidLoad() { super.viewDidLoad() grabPhotos() tableImages = createArray() tableView.delegate = self tableView.dataSource = self } func grabPhotos() { let imgManager = PHImageManager.default() let requestOptions = PHImageRequestOptions() requestOptions.isSynchronous = true requestOptions.deliveryMode = .highQualityFormat let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] let fetchResult: PHFetchResult<PHAsset> = PHAsset.fetchAssets(with: .image, options: fetchOptions) if fetchResult.count > 0 { for i in 0..<fetchResult.count { imgManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: { image, error in self.imageArray.append(image!) }) } } else { print("You got no photos!") } }}extension PhotoPopUpViewController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return imageArray.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoPopUpCell", for: indexPath) as? DataCollectionViewCell cell?.img.image = imageArray[indexPath.row] return cell! }}extension PhotoPopUpViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = collectionView.bounds.width / 3.0 let height = collectionView.bounds.height return CGSize(width: width, height: height) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 1 } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 1 }}extension PhotoPopUpViewController { func createArray() -> [PhotoPopUpCellData] { var tempData: [PhotoPopUpCellData] = [] let tableImages1 = PhotoPopUpCellData(image: UIImage(systemName: "photo")!, title: "Open from Albums") let tableImages2 = PhotoPopUpCellData(image: UIImage(systemName: "camera.fill")!, title: "Take a Photo") let tableImages3 = PhotoPopUpCellData(image: UIImage(systemName: "tray.and.arrow.up.fill")!, title: "Open last Image") tempData.append(tableImages1) tempData.append(tableImages2) tempData.append(tableImages3) return tempData }}extension PhotoPopUpViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return tableImages.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let tableImage = tableImages[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "PhotoPopUpCell") as! PhotoPopUpCell cell.setPhotoPopUp(photoPopUpCellData: tableImage) return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let tableImage = tableImages[indexPath.row] selectedTableImage = tableImage if indexPath.row == 0 { present(photoViewController, animated: false, completion: { self.photoViewController.chooseImage(self) }) } if indexPath.row == 1 { present(photoViewController, animated: false, completion: { self.photoViewController.accessVideo(self) }) } if indexPath.row == 2 { present(photoViewController, animated: false, completion: { self.photoViewController.chooseLastImage(self) }) } }}
I apologise, you are right the error is on line 05; print("photoImageView.bounds", photoImageView.bounds)The complete PhotoViewController;import Foundationimport UIKitimport Photosclass PhotoViewController: UIViewController { @IBOutlet weak var photoImageView: UIImageView! var imagePicker = UIImagePickerController() override func viewDidLoad() { super.viewDidLoad() imagePicker.delegate = self } func chooseImage(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { imagePicker.sourceType = .photoLibrary imagePicker.allowsEditing = true self.present(imagePicker,animated: true, completion: nil) } } func accessVideo(_ sender: Any) { if UIImagePickerController.isSourceTypeAvailable(.camera) { imagePicker.sourceType = .camera self.present(imagePicker, animated: true, completion: nil) } else { print("Camera not available") } } public func chooseLastImage(_ sender: Any) { let scale = UIScreen.main.scale print("photoImageView", photoImageView) print("photoImageView.bounds", photoImageView.bounds) let targetSize: CGSize? = CGSize(width: photoImageView.bounds.width * scale, height: photoImageView.bounds.height * scale) print("targetSize", targetSize) // Is it nil ? If not, what is its value let options = PHImageRequestOptions() options.isNetworkAccessAllowed = true options.deliveryMode = .highQualityFormat let imgManager = PHImageManager.default() let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key:"lastCreationDate", ascending: true)] let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: (.image), options: fetchOptions) print("targetSize for request", targetSize) //What is its value imgManager.requestImage(for: fetchResult.lastObject!, targetSize: targetSize!, contentMode: .default, options: options) { (result, info) in guard let result = result else { return } DispatchQueue.main.async(execute: { self.photoImageView.image = result }) } } }extension PhotoViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { photoImageView.image = image } dismiss(animated: true, completion: nil) } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { dismiss(animated: true, completion: nil) }}