Creating a JTAppleCalendar inside a xib view - swift

I'm trying to create a calendar using JTAppleCalendar inside a xib view because I want a paging type thing for it. On the first page is some information, and the second page is the calendar. I followed the tutorials for JTAppleCalendar on multiple sites, but my project always crashes, probably because I'm doing something wrong.
I have 3 files, a DetailViewController for setting up and displaying the pages, a dataViewController to connect the xib vars, and a CollectionViewCell for the calendar cells.
DetailViewController
import UIKit
import JTAppleCalendar
class DetailViewController: UIViewController {
var sportName: String = ""
var numClasses: Int = 0
var pages : [dataViewController]{
get {
let page1: dataViewController = Bundle.main.loadNibNamed("dataView", owner: self, options: nil)?.first as! dataViewController
page1.label.text = sportName
page1.classDuration.text = String(numClasses)
let page2: dataViewController = Bundle.main.loadNibNamed("secondDataView", owner: self, options: nil)?.first as! dataViewController
page2.calendar.calendarDataSource = self as? JTACMonthViewDataSource
page2.calendar.calendarDelegate = self as? JTACMonthViewDelegate
page2.calendar.reloadData()
return [page1, page2]
}
}
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
func configureView() {
// Update the user interface for the detail item.
if let detail = detailItem {
if let label = detailDescriptionLabel {
label.text = detail.description
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let back = UIBarButtonItem(title: "Back",style: .plain,target: self,action: #selector(backButton(_:)))
self.navigationItem.leftBarButtonItem = back
configureView()
view.bringSubviewToFront(pageControl)
setupScrollView(pages: pages)
pageControl.numberOfPages = pages.count
pageControl.currentPage = 0
}
var detailItem: String? {
didSet {
// Update the view.
configureView()
}
}
#objc
func backButton (_ sender: Any) {
performSegue(withIdentifier: "detailToList", sender: self)
}
func setupScrollView(pages: [dataViewController]){
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(pages.count), height: view.frame.height)
scrollView.isPagingEnabled = true
for i in 0 ..< pages.count {
pages[i].frame = CGRect(x: view.frame.width * (CGFloat(i)), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(pages[i])
}
}
}
extension DetailViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
}
}
extension dataViewController: JTACMonthViewDataSource, JTACMonthViewDelegate {
func configureCalendar(_ calendar: JTACMonthView) -> ConfigurationParameters {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy MM dd"
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
let startDate = formatter.date(from: "2020 01 01")!
let endDate = Date()
return ConfigurationParameters(startDate: startDate, endDate: endDate)
}
func calendar(_ calendar: JTACMonthView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTACDayCell {
let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "dateCell", for: indexPath) as! CollectionViewCell
cell.dateLabel.text = cellState.text
return cell
}
func calendar(_ calendar: JTACMonthView, willDisplay cell: JTACDayCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
let cell = cell as! CollectionViewCell
cell.dateLabel.text = cellState.text
}
}
dataViewController
import JTAppleCalendar
class dataViewController: UIView {
//Page 1
#IBOutlet weak var label: UILabel!
#IBOutlet weak var classDuration: UILabel!
//Page 2
#IBOutlet weak var calendar: JTACMonthView!
}
CollectionViewCell
import UIKit
import JTAppleCalendar
class CollectionViewCell: JTACDayCell {
#IBOutlet weak var dateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
And of course, the xib files. In DetailViewController, I moved the last extension part to dataViewController, but it didn't change anything. I'm also pretty sure I did many things wrong or inefficiently.
Can anyone help successfully implement the JTAppleCalendar inside the xib view, that would be appreciated! Thanks!

In your DetailViewController You are setting delegate and dataSource of calendar to self which is not conforming those protocols.
page2.calendar.calendarDataSource = self as? JTACMonthViewDataSource
page2.calendar.calendarDelegate = self as? JTACMonthViewDelegate
If thoose are needed to be handled in DetailViewController, I suggest you to start with implementing methods in DetailViewController not in dataViewController
extension DetailViewController: JTACMonthViewDataSource, JTACMonthViewDelegate

Related

Passing a variable with dynamic data from UITableViewCell to SwiftUI View

in my app I am storing a variable with different finger measurements. The different finger measurements have values in the UITableViewCell but they come up as nil in the SwiftUI View.
In the UITableViewCell, I made the variable a published variable. I then went to the SwiftUI View and tried #ObservedObject and then tried #StateObject when #ObservedObject didn't work. Again, logs in the UITableViewCell show values but logging in the SwiftUI View come up as nil and default to 0.
Below are snippets of code of the published var as well as the type. Then a snippet of the SwiftUI View where i try to pass the variable.
struct SaveNailImagesResponse: Codable {
var id: Int?
var leftIndexLength: Double?
var leftIndexSize: Int?
var leftIndexWidth: Double?
var leftMiddleLength: Double?
var leftMiddleSize: Int?
var leftMiddleWidth: Double?
var leftPinkyLength: Double?
var leftPinkySize: Int?
var leftPinkyWidth:
}
/// SNIPPET OF UITABLEVIEWCELL
class HandMeasurementsTableViewCell: UITableViewCell, ObservableObject {
#Published var fingerSizeData: SaveNailImagesResponse? {
didSet {
self.tableView.reloadData()
print(self.fingerSizeData?.leftIndexSize as Any)
print(self.fingerSizeData?.leftRingSize as Any)
print(self.fingerSizeData?.leftMiddleSize as Any)
}
}
}
/// HERE IS SNIPPET OF SWIFTUI VIEW: I tried passing it a 2 different ways below but comes up as nil and defaults to 0 every time
struct ResultsThumbnailView1: View {
#Environment(\.presentationMode) var presentationMode
#ObservedObject var data: HandMeasurementsTableViewCell = HandMeasurementsTableViewCell()
var body: some View {
VStack {
Text(String(self.data.fingerSizeData?.leftRingSize ?? 0))
Text("Size \(String(data.fingerSizeData?.leftIndexSize ?? 0))")
.font(.system(size: 19, weight: .bold))
}
}
}
// VIEW CONTROLLER WHERE EVERYTHING CONNECTS
class ResultsSizesViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var resultsData: SaveNailImagesResponse?
private var thumbnailButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(systemName: "camera.circle"), for: .normal)
button.tintColor = .black
button.addTarget(self, action: #selector(presentThumbnailPage), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
["HandMeasurementsTableViewCell"].forEach( {
tableView.register(UINib.init(nibName: $0, bundle: nil), forCellReuseIdentifier: $0)
})
tableView.delegate = self
tableView.dataSource = self
setNavBar(backButtonAvailable: true, title: "Results")
setUI()
thumbnailButtonConstraints()
}
#objc func presentThumbnailPage() {
let vc = UIHostingController(rootView: ResultsThumbnailTabView())
vc.modalPresentationStyle = .fullScreen
self.navigationController?.present(vc, animated: true)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HandMeasurementsTableViewCell") as? HandMeasurementsTableViewCell
let data = self.resultsData
cell?.fingerSizeData = data
if indexPath.row == 0 {
cell?.titleLabel.text = "Left Hand"
} else if indexPath.row == 1 {
cell?.titleLabel.text = "Right Hand"
}
return cell!
}
func thumbnailButtonConstraints() {
view.addSubview(thumbnailButton)
thumbnailButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
thumbnailButton.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 20),
thumbnailButton.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -20),
thumbnailButton.heightAnchor.constraint(equalToConstant: 20),
thumbnailButton.widthAnchor.constraint(equalToConstant: 20),
])
thumbnailButton.addTarget(self, action: #selector(presentThumbnailPage), for: .touchUpInside)
}
}
struct ResultsThumbnailView: View {
let resultsData: SaveNailImagesResponse
let vc = UIHostingController(rootView: ResultsThumbnailView(resultsData: resultsData))

How To Update Data in Another View Controller without Segue (SideMenu)

I am using SideMenu and I am trying to add an item to that SideMenu from another View Controller.
I store the items for SideMenu in habits object. But I have no idea how to add a new item from ADD VIEW CONTROLLER as there is no segue.
To sum up;
How can I access/edit habits object in SideMenu from "Add View Controller"
Here is my code for SideMenu;
import UIKit
import SideMenu
import FSCalendar
class MenuListController: UITableViewController {
var habits = [Habit]()
var selectedHabitIndex = 0
let darkColor = UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1)
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
tableView.backgroundColor = darkColor
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// MARK: - HABIT INITILIZAR
var dateStrings = ["2020-12-25","2020-12-24","2020-12-23","2020-12-22"]
var dateObjects = [Date]()
let dateFormatter = DateFormatter()
for date in dateStrings{
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateObject = dateFormatter.date(from: date)
dateObjects.append(dateObject!)
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
let someDate = formatter.date(from: "2020/12/29")
habits = [Habit(name: "Read a book", selectedDatesArray: dateObjects),
Habit(name: "Go for a walk", selectedDatesArray: dateObjects)
]
}
// MARK: - Number of Habits in the Table View
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return habits.count
}
// MARK: - Display Names of the Habits in the Table View
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = habits[indexPath.row].name
cell.textLabel?.textColor = .white
cell.backgroundColor = darkColor
return cell
}
}
Main View Controller
import UIKit
import SideMenu
import FSCalendar
class ViewController: UIViewController, FSCalendarDelegate, FSCalendarDelegateAppearance {
var selectedDateArray : [Date] = []
var habits = [Habit]()
var menu: SideMenuNavigationController?
var selectedHabit: Habit?
#IBOutlet weak var calendar: FSCalendar!
var selectedDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
calendar.delegate = self
calendar.scrollDirection = .vertical
calendar.allowsMultipleSelection = true
calendar.locale = NSLocale(localeIdentifier: "tr") as Locale
menu = SideMenuNavigationController(rootViewController: MenuListController())
menu?.leftSide = true
menu?.setNavigationBarHidden(true, animated: false)
SideMenuManager.default.leftMenuNavigationController = menu
SideMenuManager.default.addPanGestureToPresent(toView: self.view)
var dateStrings = ["2020-12-25","2020-12-24","2020-12-23","2020-12-22"]
var dateObjects = [Date]()
let dateFormatter = DateFormatter()
for date in dateStrings{
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateObject = dateFormatter.date(from: date)
dateObjects.append(dateObject!)
}
habits = [Habit(name: "Read a book", selectedDatesArray: dateObjects),
Habit(name: "Go for a walk", selectedDatesArray: dateObjects)
]
}
func toggleSideBar() {
present(menu!, animated: true, completion: nil)
}
#IBAction func didMenuTapped(_ sender: UIButton) {
present(menu!, animated: true, completion: nil)
}
func showSelectedDates (habit: Habit) {
calendar.select(habit.selectedDatesArray)
}
func setTitle(habit: Habit) {
title = habit.name
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
selectedDateArray.append(date)
}
func updateUI() {
setTitle(habit: selectedHabit ?? habits[0] )
showSelectedDates(habit: selectedHabit ?? habits[0])
}
}
Add Habit View Controller
import UIKit
class AddHabitViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addbuttonTapped(_ sender: UIButton) {
// NO IDEA WHAT TO PUT HERE?
self.dismiss(animated: true, completion: nil)
}
}
protocol MenuVCDataFillDelegate : class {
func addNewData(data: Habit)
}
class MenuListController : UITableViewController,MenuVCDataFillDelegate {
func addNewData(data: Habit){
habits.append(data)
}
}
Then, define your main ViewController like this:
class ViewController : UIViewController, AddHabitDelegate {
weak var menuDelegate : MenuVCDataFillDelegate?
func addMenuVC(){
let vc = MenuListController()
self.menuDelegate = vc
}
func navigateToAddHabit(){
let vc = AddHabitViewController()
vc.delegate = self
}
func newHabitAdded(data: Habit){
delegate?.addNewData(data: data)
}
}
And modify your AddHabitViewController to fill this data when added:
protocol AddHabitDelegate : class {
func newHabitAdded(data: Habit)
}
class AddHabitViewController: UIViewController {
weak var delegate : AddHabitDelegate?
func needsAddItem(data: Habit){
delegate?.newHabitAdded(data: data)
}
}
You can use closure or delegates pattern to pass your habit object. Implement the code below by checking, you can use this sample pattern.
// AddHabitViewController
typealias SuccessListener = (Habit) -> ()
var successListener: SuccessListener?
#IBAction func addbuttonTapped(_ sender: UIButton) {
self.dismiss(animated: false, completion: {
passTheHabitObj = Habit(name: "yourString", selectedDatesArray: dateObject)
self.successListener?(passTheHabitObj)
})
}
// ViewController
var habit = [HabitArray]() // use your array for data
let sb = UIStoryboard(name: "Main", bundle: nil)
if let destVC = sb.instantiateViewController(withIdentifier: "AddHabitViewController") as? AddHabitViewController {
destVC.successListener = { habitObj in
habit.append(habitObj)
}
thanks all for the answers. I tried both approaches but could not make it work.
Using the notification center solved my problem;
In AddHabitVC;
NotificationCenter.default.post(name: Notification.Name("ourCustom"), object: textField.text)
In SideMenuVC:
var observer : NSObjectProtocol?
observer = NotificationCenter.default.addObserver(forName: Notification.Name("ourCustom"), object: nil, queue: .main, using: { (notification) in
guard let object = notification.object as? String else {
return
}
self.items.append(object)
self.tableView.reloadData()
})
Thanks.

Best Approach to make Calculation in tableviewcells and sums up in UILabel

My Cart looks like this
What should be the best approach to do calculation of all cells and sums up total Amount label
Cart Working like this :
Increment in cell's item doubles the value of price label but when i dequeue new cell it already has that increment value
When tried to work with custom delegate , Delegate always shows nil
What should I do ? why my delegate is always nil ?
TableViewCell
class ShoppingCartCell: UITableViewCell {
#IBOutlet weak var cellView:UIView!
#IBOutlet weak var productImageView:UIImageView!
#IBOutlet weak var productName:UILabel!
#IBOutlet weak var brandName:UILabel!
#IBOutlet weak var productPrice:UILabel!
#IBOutlet weak var modifier1Lbl:UILabel!
#IBOutlet weak var modifier2Lbl:UILabel!
#IBOutlet var counterBtns:[UIButton]!
#IBOutlet weak var counterLbl:UILabel!
var delegate : cellDelegateFunc?
override func layoutMarginsDidChange() {
super.layoutMarginsDidChange()
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
productImageView.layer.cornerRadius = productImageView.frame.height / 4
cellView.roundUIViewWithShadow(cornerRadius: 4, shadowColor: .darkGray)
cellView.layer.masksToBounds = false
cellView.layer.shadowColor = UIColor.lightGray.cgColor
cellView.layer.shadowOpacity = 1
cellView.layer.shadowOffset = .zero
}
override func awakeFromNib() {
super.awakeFromNib()
cellView.layer.cornerRadius = cellView.frame.height / 16
productImageView.layer.cornerRadius = productImageView.frame.height / 16
}
#IBAction func counter(_ sender:UIButton){
self.delegate?.countItems(self)
}
}
CartViewController (Particular Portion)
class ShoppingBagVC: UIViewController , cellDelegateFunc {
func countItems(_ cell: ShoppingCartCell) {
print("print")
}
}
Protocol
protocol cellDelegateFunc : class {
func countItems(_ cell:ShoppingCartCell)
}
CellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if cartAllData[indexPath.row].deal.data != nil {
let cell = cartTableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath) as! ShoppingCartDealCell
cell.originalPrice = Int(cartAllData[indexPath.row].deal.data!.dealPrice)
cell.productName.text = cartAllData[indexPath.row].deal.data?.dealName
cell.productPrice.text = "Rs.\(String(cell.originalPrice))"
cell.freeItem.text = cartAllData[indexPath.row].deal.data?.freeProduct
cell.productImageView?.sd_setImage(with: URL(string: cartAllData[indexPath.row].deal.data!.imageURL), completed: nil)
return cell
} else {
let cell = cartTableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! ShoppingCartCell
var originalPrice = Int()
var price : Int = 2{
didSet {
cell.productPrice.text = "Rs.\(String(price))"
}
}
var count : Int = 1{
didSet {
cell.counterLbl.text = String(count)
price = originalPrice * count
}
}
if let value = cartAllData[indexPath.row].deal.data?.quantity {
cell.counterLbl.text = String(value)
}
if let value = cartAllData[indexPath.row].product.data?.quantity {
cell.counterLbl.text = String(value)
}
originalPrice = Int(cartAllData[indexPath.row].product.data!.productBasePrice)
cell.productPrice.text = "Rs.\(String(originalPrice))"
cell.productName.text = cartAllData[indexPath.row].product.data?.productName
cell.productImageView?.sd_setImage(with: URL(string: cartAllData[indexPath.row].product.data!.imageURL), completed: nil)
cell.modifier1Lbl.text = cartAllData[indexPath.row].product.data?.modifier1
cell.modifier2Lbl.text = cartAllData[indexPath.row].product.data?.modifier2
return cell
}
}
As #joakim said in comment you are doing calculations in a UI! and it's not a correct way
When a UITableView scrolls every cell will reload because of reusing and every cell will lose its state because it loads again. so you must store state of each cell in a Model and pass it to your cell each time a cell loads.
As you requested The Best approach would be to use a ViewModel or a Presenter to store state of a View (here your cell) and in every load you feed that View (for example in your cellForRow) with the stored States or Properties

How to create a new collectionView when switching to another calendarView

I am having trouble trying to create a new collection view. I want to effectively have a collectionView with unique properties and then when I click on a date in my view controller it changes to a effectively a blank collectionView template so that the user can then put it there recipes.
How would I go about changing the collectionView (when user clicked on a date), change to a collection-view template and then save when the user puts in data?
Here is the code for the controller along with a picture example:
import UIKit
import GCCalendar
class CalendarViewController123: UIViewController, UICollectionViewDelegate {
// MARK: Properties
fileprivate var calendarView: GCCalendarView!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var datelabel: UILabel!
#IBOutlet weak var open: UIBarButtonItem!
#IBAction func trytoday(_ sender: Any) {
self.calendarView.select(date: Date())
}
}
// MARK: - View
extension CalendarViewController123 {
override func viewDidLoad() {
super.viewDidLoad()
open.target = revealViewController()
open.action = #selector(SWRevealViewController.revealToggle(_:))
self.addToolbar()
self.addCalendarView()
self.addConstraints()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for:.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
}
// MARK: - Toolbar
extension CalendarViewController123 {
fileprivate func addToolbar() {
self.navigationController!.isToolbarHidden = false
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let displayMode = UIBarButtonItem(title: "Display Mode", style: .plain, target: self, action: #selector(self.displayMode))
self.toolbarItems = [ space, displayMode]
}
#objc func displayMode() {
self.calendarView.displayMode = (self.calendarView.displayMode == .month) ? .week : .month
}
}
// MARK: - Calendar View
fileprivate extension CalendarViewController123 {
func addCalendarView() {
self.calendarView = GCCalendarView()
self.calendarView.delegate = self
self.calendarView.displayMode = .week
self.calendarView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.calendarView)
}
}
// MARK: - Constraints
fileprivate extension CalendarViewController123 {
func addConstraints() {
self.calendarView.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 2).isActive = true
self.calendarView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.calendarView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
self.calendarView.heightAnchor.constraint(equalToConstant: 325).isActive = true
}
}
// MARK: - GCCalendarViewDelegate
extension CalendarViewController123: GCCalendarViewDelegate {
func calendarView(_ calendarView: GCCalendarView, didSelectDate date: Date, inCalendar calendar: Calendar) {
let dateFormatter = DateFormatter()
dateFormatter.calendar = calendar
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "MMM dd", options: 0, locale: calendar.locale)
//yyyy
// self.navigationItem.title = dateFormatter.string(from: date)
self.datelabel.text = dateFormatter.string(from: date)
}
}
The Green is the collectionView on a view controller
It depends on what data you are showing and how you are retrieving it. If you can provide more information I will update my answer accordingly.
1. Select Date
#IBAction func trytoday(_ sender: Any) {
self.calendarView.select(date: Date())
self.fetchData(forDate: selectedDate)
}
2. Fetch Data
func fetchData(forDate date: Date) {
//Fetch data and return array of objects
self.objects = retreivedObjects
self.collectionView.reloadData()
}
3. Load Data
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objects.count
}
4. Setup Cell with Data
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? Cell else { return UICollectionViewCell}
cell.configure(withObject: objects[indexPath.item])
return cell
}

Can't convert value of type 'String' to expected argument type 'UIImage'. UIImagePicker puts into collectionView - want to view in a detailed VC?

I'm trying to create a photo album via UIImagePicker into a CollectionView and cannot get it to segue to that same photo again in a detailed UIViewController. Pulling my hair out and this is just a tutorial as I have just started coding!
Can anyone tell me what I'm doing wrong?
Here is my ViewController:
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate {
#IBOutlet private weak var addButton: UIBarButtonItem!
#IBOutlet private weak var collectionView:UICollectionView!
#IBOutlet private weak var trashButton:UIBarButtonItem!
var testItems = [Person]()
var stormTrooperCollectionArray: [UIImage] = [#imageLiteral(resourceName: "StormTrooper-3052-423a-8c57-7220081e1585_800x"), #imageLiteral(resourceName: "ST3"), #imageLiteral(resourceName: "ST2"), #imageLiteral(resourceName: "ST4")]
#IBAction func addItem() {
addNewPerson()
}
#IBAction func trashItem(_ sender: Any) {
if let selectedItems = collectionView.indexPathsForSelectedItems {
let itemsForDeletion = selectedItems.map{$0.item}.sorted().reversed()
for item in itemsForDeletion {
testItems.remove(at: item)
}
collectionView.deleteItems(at: selectedItems)
}
}
#objc func refresh() {
addItem()
collectionView.refreshControl?.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Set up a 3-column Collection View
let width = (view.frame.size.width - 20) / 3
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width:width, height:width)
// Refresh Control
let refresh = UIRefreshControl()
refresh.addTarget(self, action: #selector(self.refresh), for: UIControlEvents.valueChanged)
collectionView.refreshControl = refresh
// Edit
navigationItem.leftBarButtonItem = editButtonItem
navigationController?.isToolbarHidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailSegue" {
if let dest = segue.destination as? DetailsViewController,
let index = sender as? IndexPath {
dest.detailedImageHi = stormTrooperCollectionArray [index.row]
}
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
navigationController?.isToolbarHidden = !editing
addButton.isEnabled = !editing
trashButton.isEnabled = editing
collectionView.allowsMultipleSelection = editing
let indexes = collectionView.indexPathsForVisibleItems
for index in indexes {
let cell = collectionView.cellForItem(at: index) as! CollectionViewCell
cell.isEditing = editing
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UIImagePickerControllerDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stormTrooperCollectionArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
//cell.titleLabel.text = stormTrooperCollectionArray[indexPath.row]
cell.selectionImage.image = stormTrooperCollectionArray[indexPath.row]
cell.isEditing = isEditing
return cell
}
#objc func addNewPerson() {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }
let imageName = UUID().uuidString
let imagePicture = getDocumentsDirectory()
if let jpegData = UIImageJPEGRepresentation(image, 80) {
try? jpegData.write(to: imagePicture)
}
//let detailedItem = Person(imageHi: imageName)
//testItems.append(detailedItem)
let detailedItem = Person(imageHi: imageName)
//KEEPS THROWING AN ERROR HERE WHICH SAYS: Cannot convert value of type 'String' to expected argument type 'UIImage'
stormTrooperCollectionArray.append(detailedItem)
collectionView?.reloadData()
dismiss(animated: true)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if !isEditing {
performSegue(withIdentifier: "DetailSegue", sender: indexPath)
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
}
Here is my VC for the Cell in the CollectionView:
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var selectionImage: UIImageView!
}
Here is my VC for the Detailed View Controller:
import UIKit
class DetailsViewController: UIViewController {
var selection: String!
var detailedImageHi: UIImage!
#IBOutlet private weak var detailsLabel: UILabel!
#IBOutlet private weak var detailedImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
detailsLabel.text = selection
detailedImage.image = detailedImageHi
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is my VC for the NSObject Swift File:
import UIKit
class Person: NSObject {
var imageHi: UIImage
init(imageHi: UIImage){
self.imageHi = imageHi
}
}
In your code the UIImage is image and not imageName:
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }
So all you have to do is pass the right argument to the constructor of Person:
let detailedItem = Person(imageHi: image)
imageName is a random string generated via UUID().uuidString, and used in this code to save the image to the documents directory with a random and unique name.