swiftjtapplecalendar

JTAppleCalendar fails to trigger didSelectDate after update to 8.0


I'm using JTAppleCalendar to add a calendar to a view in my app. I had everything working but after I updated to 8.0 I can't link the controllers properly.

Here is the error I get

Assertion failed: Attemped to access calendar when Datasource/delegate is not set yet. Returning default value: file /Users/studio/Desktop/my_app/Pods/JTAppleCalendar/Sources/JTAppleCalendar/JTACVariables.swift, line 109 2019-09-23 00:51:42.437357+0300 Ways[4044:97207] Assertion failed: Attemped to access calendar when Datasource/delegate is not set yet. Returning default value: file /Users/studio/Desktop/my_app/Pods/JTAppleCalendar/Sources/JTAppleCalendar/JTACVariables.swift, line 109

Here is my controller

import UIKit
import JTAppleCalendar

class LandingPageViewController: UIViewController {

    let formatter = DateFormatter()

    var queryID: String = ""

    var targetDate: Date?
    var dateSelected: Date = Date()
    var timeSelected: Date = Date()

    @IBOutlet weak var calendarView: JTACMonthView!

    @IBOutlet weak var yearLabel: UILabel!

    @IBAction func calendarSaveButton(_ sender: Any) {
        if let finalDate = combineDateWithTime(date: dateSelected, time: timeSelected) {
            QueryModel().addTargetDate(id: queryID, targetDate: finalDate)
            dismiss(animated: true, completion: nil)
        }
    }

    func combineDateWithTime(date: Date, time: Date) -> Date? {
        let calendar = NSCalendar.current

        let dateComponents = calendar.dateComponents([.year, .month, .day], from: date)
        let timeComponents = calendar.dateComponents([.hour, .minute, .second], from: time)

        var mergedComponments = DateComponents()
        mergedComponments.year = dateComponents.year!
        mergedComponments.month = dateComponents.month!
        mergedComponments.day = dateComponents.day!
        mergedComponments.hour = timeComponents.hour!
        mergedComponments.minute = timeComponents.minute!
        mergedComponments.second = timeComponents.second!

        return calendar.date(from: mergedComponments)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupCalendarView()

        formatter.timeZone = Calendar.current.timeZone
        formatter.locale = Calendar.current.locale

        self.calendarView.scrollToDate(dateSelected, animateScroll: false)
        self.calendarView.selectDates([dateSelected])
    }

    @objc func handleDatePicker(sender: UIDatePicker) {
        timeSelected = sender.date;
    }

    func setupCalendarView(){
        calendarView.minimumLineSpacing = 0
        calendarView.minimumInteritemSpacing = 0

        calendarView.visibleDates { (visibleDates) in
            self.setupViewsFromCalendar(from: visibleDates)
        }
    }

    func setupViewsFromCalendar(from: DateSegmentInfo){
        let date = from.monthDates.first!.date

        formatter.dateFormat = "yyyy"
        yearLabel.text = formatter.string(from: date)

        formatter.dateFormat = "MMMM"
    }

    func handleCellSelection(myCustomCell: CalendarCell, cellState: CellState, date: Date) {
        myCustomCell.dateLabel.text = cellState.text

        if cellState.isSelected {
            dateSelected = date
            myCustomCell.selectedDay.isHidden = false
            myCustomCell.selectedDay.backgroundColor = UIColor.orange
        }else {
            myCustomCell.selectedDay.isHidden = true
        }
    }

    func handleCellTextColor(myCustomCell: CalendarCell, cellState: CellState, date: Date){
        if cellState.isSelected{
            myCustomCell.dateLabel.textColor = UIColor.white
        }else{
            if cellState.dateBelongsTo == .thisMonth {
                myCustomCell.dateLabel.textColor = UIColor.black
            }else{
                myCustomCell.dateLabel.textColor = UIColor.gray
            }
        }
    }

    func handleTodayCell(myCustomCell: CalendarCell, cellState: CellState, date: Date){
        formatter.dateFormat = "dd MM yyyy"

        let todayDateString = formatter.string(from: Date())
        let cellDateString = formatter.string(from: cellState.date);

        if todayDateString == cellDateString {
            // Checks to see if today is the current cell and apply different styling
            myCustomCell.selectedDay.isHidden = false
            myCustomCell.selectedDay.backgroundColor = UIColor.blue
            myCustomCell.dateLabel.textColor = UIColor.white
        }
    }
}

extension LandingPageViewController:JTACMonthViewDataSource {
    func calendar(_ calendar: JTACMonthView, willDisplay cell: JTACDayCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
        let myCustomCell = cell as! CalendarCell
        handleCellSelection(myCustomCell: myCustomCell, cellState: cellState, date: date)
    }

    func configureCalendar(_ calendar: JTACMonthView) -> ConfigurationParameters {

        let startDate = Date()
        //print(startDate);

        let yearsToAdd = 10
        let endDate = Calendar.current.date(byAdding: .year, value: yearsToAdd, to: startDate)

        let params = ConfigurationParameters(
            startDate: startDate,
            endDate: endDate!,
            generateInDates: .forAllMonths,
            generateOutDates: .tillEndOfRow
        )

        return params
    }
}

extension LandingPageViewController: JTACMonthViewDelegate {
    func calendar(_ calendar: JTACMonthView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTACDayCell {
        let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CalendarCell", for: indexPath) as! CalendarCell

        handleCellSelection(myCustomCell: cell, cellState: cellState, date: date)
        handleCellTextColor(myCustomCell: cell, cellState: cellState, date: date)
        handleTodayCell(myCustomCell: cell, cellState: cellState, date: date)

        return cell
    }

    func calendar(_ calendar: JTACMonthView, didSelectDate date: Date, cell: JTACDayCell?, cellState: CellState) {
        guard let validCell = cell as? CalendarCell else { return }
        handleCellSelection(myCustomCell: validCell, cellState: cellState, date: date)
        handleCellTextColor(myCustomCell: validCell, cellState: cellState, date: date)
    }

    func calendar(_ calendar: JTACMonthView, didDeselectDate date: Date, cell: JTACDayCell?, cellState: CellState) {
        guard let validCell = cell as? CalendarCell else { return }
        handleCellSelection(myCustomCell: validCell, cellState: cellState, date: date)
        handleCellTextColor(myCustomCell: validCell, cellState: cellState, date: date)
        handleTodayCell(myCustomCell: validCell, cellState: cellState, date: date)
    }

    func calendar(_ calendar: JTACMonthView, shouldSelectDate date: Date, cell: JTACDayCell?, cellState: CellState) -> Bool {
        if (cellState.date.timeIntervalSince(Date()) > -86400) {
            return true
        }else {
            return false
        }
    }

    func calendar(_ calendar: JTACMonthView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
        setupViewsFromCalendar(from: visibleDates)
    }
}

I just changed the class names to the new version.

enter image description here


Solution

  • I think you missed the migration guide. In there it tells you to rename your functions and gives you a list of functions to rename.

    In your case of didSelect/didDeselect, it should be renamed to

    func calendar(_ calendar: JTACMonthView, didSelectDate date: Date, cell: JTACDayCell?, cellState: CellState, indexPath: IndexPath)
    func calendar(_ calendar: JTACMonthView, didDeselectDate date: Date, cell: JTACDayCell?, cellState: CellState, indexPath: IndexPath)
    

    Because you didnt rename them, they are not called. Please rename the others as well where needed.

    In regards to the DataSource error, what happens when you delete the DataSource/Delegate from InterfaceBuilder and reconnect them (could be IB messing up)?