#StackBounty: #object-oriented #design-patterns #swift #macos Trying (and failing) to implement the best conventions on OOP Swift

Bounty: 100

I’m making a MacOS app that will do some analysis on the user’s calendar data. For now it only supports Apple’s native calendar (EventKit), but I will later add support to Google, outlook, etc.

Models/Events/Base.swift:

import Foundation

struct EventData {
    var title: String;
    var startDate: Date;
    var endDate: Date;
    var organizerName: String;
    var notes: String;
    var location: String;        
}

struct CalendarData {
    var title: String;
    var isSubscribed: Bool;
}

class Events {
    init() {
        checkForAuthorization();
    }

    func checkForAuthorization() {}
    func requestAccess() {}
    func getCalendars() -> [CalendarData] {
        return [];
    }
    func getEvents(calendarName: String, from: Date, to: Date) -> [EventData] {
        return [];
    }
}

Models/Events/iCal.swift:

import Foundation
import EventKit

class iCal: Events {

    let eventStore = EKEventStore();
    var calendars: [EKCalendar]?;

    override func checkForAuthorization() {
        let status = EKEventStore.authorizationStatus(for: EKEntityType.event);

        switch (status) {
            case EKAuthorizationStatus.notDetermined:
                self.requestAccess();
                break;
            case EKAuthorizationStatus.authorized:
                break;
            case EKAuthorizationStatus.restricted, EKAuthorizationStatus.denied:
                break;
         }
    }

    override func requestAccess() {
        eventStore.requestAccess(to: EKEntityType.event, completion:{ (accessGranted: Bool, error: Error?) in
            if accessGranted == true {
                print("Granted")
            } else {
                print("Denied")
            }
        });
    }

    override func getCalendars() -> [CalendarData] {
        let _cals = self.eventStore.calendars(for: .event);
        var cals: [CalendarData] = [];

        for cal: EKCalendar in _cals {
            cals.append(CalendarData(title: cal.title, isSubscribed: cal.isSubscribed));
        }
        return cals;
    }
    override func getEvents(calendarName: String, from: Date, to: Date) -> [EventData] {
        let cals = self.eventStore.calendars(for: .event);
        var events: [EventData] = [];

        if let calIndex: Int = cals.firstIndex(where: { $0.title == calendarName }) {
            let selectedCalendar: EKCalendar = cals[calIndex];

            let predicate = eventStore.predicateForEvents(withStart: from, end: to, calendars: [selectedCalendar])
            let _events = eventStore.events(matching: predicate) as [EKEvent];

            for ev: EKEvent in _events {
                events.append(
                    EventData(
                        title: ev.title,
                        startDate: ev.startDate,
                        endDate: ev.endDate,
                        organizerName: ev.organizer?.name ?? "",
                        notes: ev.notes ?? "",
                        location: ev.location ?? ""
                    )
                );
            }

        }

        return events;
    }
}

And I use this class like this:

let calendar = iCal();
for cal in calendar.getCalendars() {
   print("****** (cal.title) *******n");
   print(calendar.getEvents(calendarName: cal.title, from: Calendar.current.date(byAdding: .day, value: -2, to: Date())!, to: Calendar.current.date(byAdding: .day, value: 1, to: Date())!))
}

This works, but it feels very wrong…
I know the semi-colons are not needed, but I always used it in other languages and the linting will delete them anyway after.

Questions:

  1. How can I improve this?
  2. Would it be better to instantiate the class
    Events, by passing the calendar type as an argument (eg. iCal,
    outlook, etc)
  3. Are those structs ok? As in should they go in another
    file?

Thank you


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.