1

I am using SwiftUI, UIKit and external library CalendarKit in my project. The problem is that events don't load (while initializing ) on first view ( first load ) of calendar ( the current day view ). When I change date in the NavBar, update event or create new event everything works fine. Events are reloading and are showed up on screen.

I have few classes in my projects. First is CalendarScreen which renders the SwiftUI view, ViewModel of CalendarScreen which loads data fetched from API. Service which provides repository and Repository class which runs URLRequest. The UIKit class of DayViewController where everything is going in:

class CalendarViewController: DayViewController {
  convenience init(viewModel: CalendarScreen.ViewModel) {
    self.init()
    self.viewModel = viewModel
  }
  var viewModel = CalendarScreen.ViewModel()
  override func viewDidLoad() {
    super.viewDidLoad()
    reloadData()
  }
  override func reloadData() {
    dayView.timelinePagerView.pagingViewController.children.forEach({ (controller) in
      if let controller = controller as? TimelineContainerController {
        controller.timeline.layoutAttributes = eventsForDate(Date()).map(EventLayoutAttributes.init)
      }
    })
  }
  override func eventsForDate(_ date: Date) -> [EventDescriptor] {
    return viewModel.fetchCalendarEvents { _ in
      var calendarKitEvents = [Event()]
      calendarKitEvents = self.viewModel.calendarEvents.compactMap { item in
        let event = Event()
        event.dateInterval = DateInterval(
          start: self.dateTimeFormat.date(from: item.start) ?? Date(),
          end: self.dateTimeFormat.date(from: item.end) ?? Date())
        event.color = UIColor(InvoiceColor(title: item.title))
        event.isAllDay = false
        event.text = item.title
        return event
      }
      self.eventsOnCeldanr = calendarKitEvents
      return self.eventsOnCeldanr
    }
  }
}

And the classes corresponding to my APICall the main function is func fetchCalendarEvents which return Events to my Controller

class Agent {
  let session = URLSession.shared
  func run<T: Decodable>(_ request: URLRequest) -> AnyPublisher<T, Error> {
    return
      session
      .dataTaskPublisher(for: request)
      .decode(type: T.self, decoder: JSONDecoder())
      .receive(on: DispatchQueue.main)
      .eraseToAnyPublisher()
  }
}

struct CalendarRepository {
  private let agent = Agent()
  func getEvents() -> AnyPublisher<[CalendarEvent], Error> {
    let urlString = "\(calendarurl)"
    let url = URL(string: urlString)!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    return agent.run(request)
  }
}

struct CalendarService {
  private var calendarRepository = CalendarRepository()
  func getEvents() -> AnyPublisher<[CalendarEvent], Error> {
    return calendarRepository.getEvents()
  }

  extension CalendarScreen {
    class ViewModel: ObservableObject {
      let calendarService = CalendarService()
      @Published var calendarEvents: [CalendarEvent]
      @Published var events: [Event]
      var cancellable: AnyCancellable?
      init() {
        self.calendarEvents = [CalendarEvent()]
        self.events = []
      }
      func fetchCalendarEvents(_ completion: @escaping ([EventDescriptor]) -> [EventDescriptor])
        -> [EventDescriptor]
      {
        cancellable = calendarService.getEvents()
          .sink(
            receiveCompletion: { _ in },
            receiveValue: {
              calendarEvents in self.calendarEvents = calendarEvents
              NotificationCenter.default.post(name: .onEventLoaded, object: nil)
              self.createEvents()
              completion(self.events)
            })
        return events
      }
      func createEvents() {
        self.events = self.calendarEvents.compactMap({ (item) in
          var event = Event()
          event.dateInterval = DateInterval(
            start: self.dateTimeFormat.date(from: item.start)!,
            end: self.dateTimeFormat.date(from: item.end)!)
          event.color = UIColor(InvoiceColor(title: item.title))
          event.isAllDay = false
          event.text = item.title
          return event
        })
      }
    }
  }
}

So the problem is when I load view for the first time the reloadDate() returning empty [] array.While i try to debug events are in variable calendarKitEvents but without sucessful return t Events don't show up on my calendar.enter image description here

But when I switch dates lets say for next date and switch back to current day events show up enter image description here

I am thinking that I don't know how to proper load Events on init view of Calendar. I tried to use reloadData() in every possible moment but without success. Moreover I tried to reloadData() in updateUIViewController. Events show up but it gives me a infinite loop of request to fetch data.

XoliKnight
  • 61
  • 6
  • Thanks for only including relevant classes, but this is a lot to read. Try to create a minimal example, or at least remove irrelevant code, such as import statements, print statements, and view modifiers. Much more likely to get an answer :) – Stoic Nov 17 '22 at 22:24
  • I modified my question to your recommendations @Stoic – XoliKnight Nov 18 '22 at 09:01
  • @XoliKnightPlease please add implementation of reload data – teja_D Nov 18 '22 at 09:11
  • @teja_D `reloadData` functionallity coming from `CalendarKit` event which is avaliable on GitHub but i added it aswell. I Also added `updateTimeline` function to my post wich also comes from the library – XoliKnight Nov 18 '22 at 09:16
  • @XoliKnight Could please check if self.updateTimeline(controller.timeline) statement is getting executed or not using breakpoints or log – teja_D Nov 18 '22 at 09:20
  • @teja_D yes, whem i am loading the screen for first time `updateTimeline` statement is getting executed. I used the `breakpoints` because i dont know how use `log` – XoliKnight Nov 18 '22 at 09:24
  • @XoliKnight Where is your API call to get the data from server? – teja_D Nov 18 '22 at 09:27
  • @teja_D i added API call to my question you can check it out but it is simple request with `completion` return – XoliKnight Nov 18 '22 at 09:32
  • @XoliKnight How does your API request is getting called on viewDidLoad()? – teja_D Nov 18 '22 at 09:35
  • @teja_D the `override func eventsForDate` function is used when `reloadData()` is called at least from what I can infer – XoliKnight Nov 18 '22 at 09:37
  • 1
    @XoliKnight So have you checked if that overridden method is getting called after viewDidLoad()? – teja_D Nov 18 '22 at 09:40
  • @teja_D its called but after that `eventsForDate` it is not called as usual. You found a problem any tips to solve it? – XoliKnight Nov 18 '22 at 09:43
  • @teja_D so i rewrite `reloadData` function and in first call variable `events` is empty – XoliKnight Nov 18 '22 at 09:57

0 Answers0