Swift:太多的静态功能



我有一个从事件存储中检索到的日历项(模型(的类。我还没有为AppDelegate或ViewControllers实施任何委派。

我在此类中的所有方法都是静态函数 - 主要原因是我可以从AppDelegate或VC"看到"它们。我怀疑:

1(我需要使它成为单身人士 - 唯一的功能是从事件店检索日历项目并发布到UI

2(学习如何更好地编码 - 也许在AppDelegate和VC

中创建类实例

这对我来说仍然很模糊 - 不确定发布代码是否有帮助,但是课程有一堆" static func .... dosomething(({...}" andAppDelegate和VC称为" className.dosomething((..."

我准备重构课程代码,以为单身人士会起作用 - 或者,也许一切都很好...

编辑:添加代码:

import Foundation
import EventKit

class Calendars: NSObject {
    enum calendarAuthState {
        case restricted
        case authorized
        case denied
        case notDetermined
    }
    struct Calendar {
        var id: String
        var color: NSColor
        var title: String
        var isUserActive: Bool
        var events: [EventItem]

    }
    struct EventItem {
        var originalStartDate: Date
        var date: String
        var title: String
        var isAllDayEvent: Bool
    }
    static var calendarState: calendarAuthState = .notDetermined
    static var eventStore = EKEventStore()
    static var currentCalendars = [Calendar]()

    //MARK: Check Calendar Authorization Status
    static func calendarAuthorizationStatus() {
        let status = EKEventStore.authorizationStatus(for: .event)
        switch (status) {
        case EKAuthorizationStatus.notDetermined:
            // This happens on first-run
            calendarState = .notDetermined
        case EKAuthorizationStatus.authorized:
            calendarState = .authorized
        case EKAuthorizationStatus.restricted:
            self.requestAccessToCalendar()
            calendarState = .restricted
        case EKAuthorizationStatus.denied:
            self.requestAccessToCalendar() 
            calendarState = .denied
        }
    }
    static func requestAccessToCalendar() {
        self.eventStore.requestAccess(to: EKEntityType.event, completion: {
            (accessGranted: Bool, error: Error?) in
            if accessGranted == true {
                DispatchQueue.main.async(execute: {
                    self.calendarState = .authorized
                })
            } else {
                DispatchQueue.main.async(execute: {
                    self.calendarState = .denied
                })
            }
        })
    }
        //MARK: Do the two below
        static func createMenuFromCalendars() {
            guard calendarState == .authorized else {
                return
            }
            let calendars = self.returnCalendars()
            guard calendars.count >= 0 else {
                return
            }
            self.addCalendarsToMenuItems(from: calendars)
        }
    //MARK: First, return the calendar titles from the Store
    static func returnCalendars() -> [Calendar] {
        guard self.calendarState == .authorized else {
            return[]
        }
        let calendars = self.eventStore.calendars(for: .event)
        for calendar in calendars {
            self.currentCalendars.append(Calendar(id: calendar.calendarIdentifier, color: calendar.color, title: calendar.title, isUserActive: false, events: []))
        }
        return self.currentCalendars
    }
    //MARK: Next, send those to the Menu for MenuItem creation
    static func addCalendarsToMenuItems(from calendars:[Calendar]) {
        let appDelegate = NSApplication.shared.delegate as! AppDelegate
        let appMainMenu = NSApp.mainMenu
        if let calendarMenu = appMainMenu?.item(withTitle: "Calendars") {
            let calendarSubMenu = calendarMenu.submenu
            for calendar in calendars {
                let menuItem = calendarSubMenu?.addItem(withTitle: calendar.title, action: #selector(appDelegate.actionFromSelectedCalendar) , keyEquivalent: "")
                menuItem?.isEnabled = true
                menuItem?.state = .off
                menuItem?.target = appDelegate.self
                menuItem?.toolTip = calendar.id
            }
        }
    }
     class func retrieveCalendarEvents() {
        guard self.calendarState == .authorized || !(self.currentCalendars.isEmpty) else {
            return
        }
        let startDate = Date()
        let endDate = Date(timeIntervalSinceNow: 4*24*3600)
        var activeCalendars = findUserActiveCalendars(in: currentCalendars)
        //need to flush the events at this stage or they'll pile
        guard !((activeCalendars?.isEmpty)!) else {
            return
        }
        var eventCalendar = [EKCalendar]()
        for dayBookCalendar in activeCalendars! {
            // much of the risk here is unwrapping optionals unsafely!!!!! - refactor this and other please
            eventCalendar.append(self.eventStore.calendar(withIdentifier: dayBookCalendar.id)!)
            let eventPredicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: eventCalendar)
            let returnedEvents = eventStore.events(matching: eventPredicate)
            let calendarIndex = findCalendarIndex(by: dayBookCalendar.id, in: currentCalendars)
            for event in returnedEvents {
                let eventItems = eventItem(from: event)
                currentCalendars[calendarIndex!].events.append(eventItems)
            }
        }
    }
    //MARK: Helper methods and stuff
    static func changeUserCalendarState(with id:String, state:Bool) {
        guard !(currentCalendars.isEmpty) else {
            return
        }
        let calendarIndex = findCalendarIndex(by: id, in:self.currentCalendars)
        if let calendarIndex = calendarIndex {
            currentCalendars[calendarIndex].isUserActive = !state
            retrieveCalendarEvents()
        }
    }
    static func findCalendarIndex(by id:String, in calendarArray: [Calendar]) -> Int? {
        return calendarArray.index(where: {$0.id == id})
    }
    static func findUserActiveCalendars(in calendarArray: [Calendar]) -> [Calendar]? {
        return calendarArray.filter({$0.isUserActive == true})
    }
//    static func flushEventsFromCalendar(in calendarArray: inout [Calendar]) {
//        calendarArray.map({$0.events.removeAll()})
//    }
    static func eventItem(from events:EKEvent) -> EventItem {
        return EventItem(originalStartDate: events.startDate, date:eventTime(from: events.startDate), title: events.title!, isAllDayEvent: events.isAllDay)
    }
    static func parseCalendarEvents(from events:[EKEvent]) -> [EventItem] {  //can this be variadic?
        var calendarEvents = [EventItem]()
        for event in events {
            calendarEvents.append(eventItem(from: event))
        }
        return calendarEvents
    }
    static func eventTime(from date:Date) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.timeStyle = .short
        dateFormatter.locale = Locale.current
        let stringTime = dateFormatter.string(from: date)
        return stringTime
    }

}

''

我认为您对面向对象的编程犯了一个基本错误。在您的日历课中,您似乎已经封装了访问用户日历的所有代码。然后您似乎已经推理了:"好吧,此代码需要从任何地方都可召唤。因此,我班级的所有成员都必须是全局(静态/班级(。"

这是一个错误。这样的封装没有错。确实,这是一件好事。但是,到达使用的方式是使用助手实例。例如,假设您在视图控制器中(毕竟很可能是(。然后它可以拥有一个属性:

let calendarHelper = Calendars()

现在,您的成员可以(并且应该(成为实例成员。请记住,相同类型的实例每个人都可以彼此分开保持状态;那是他们封装的一部分。您将想要那种能力。

如果您认为您需要静态/班级成员的基本原因是您只需要一个一个 ekeventStore实例来实例应用程序的寿命,然后将lobalness/staticness推到那个对象(例如,通过"共享" ekeventStore和访问它的方法(,让所有内容 else 为正常实例成员。

您所说的话,怀疑1(是正确的 - 您需要使用单身人士:

class CalendarService {
    private var eventStore = EKEventStore()
    //Static shared instance, this is your singleton 
    static var sharedInstance =  CalendarService()
    //Your public methods for adding events can go here
    public func doSomething() {
        //...
    }
    //As can your private methods for producing, deleting and editing calendar events + checking permissions
}

用法:

CalendarService.sharedInstance.doSomething()

没有您现有代码的特定示例,我不能说更多。

最新更新