Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 斯威夫特:静态函数太多了?_Swift_Macos - Fatal编程技术网

Swift 斯威夫特:静态函数太多了?

Swift 斯威夫特:静态函数太多了?,swift,macos,Swift,Macos,我有一个表示从事件存储中检索到的日历项(模型)的类。我还没有为AppDelegate或ViewController实现任何委托 我在这个类中的所有方法都是静态函数——主要原因是我可以从AppDelegate或VC中“看到”它们。我怀疑: 1) 我需要将其设置为singleton,它唯一的功能是从eventStore检索日历项并发布到UI 2) 了解如何更好地编写代码-可能在AppDelegate和VC中创建类的实例 这对我来说仍然很模糊-不确定发布代码是否有帮助,但该类有一堆“static fu

我有一个表示从事件存储中检索到的日历项(模型)的类。我还没有为AppDelegate或ViewController实现任何委托

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

1) 我需要将其设置为singleton,它唯一的功能是从eventStore检索日历项并发布到UI

2) 了解如何更好地编写代码-可能在AppDelegate和VC中创建类的实例

这对我来说仍然很模糊-不确定发布代码是否有帮助,但该类有一堆“static func….doSomething(){…}”,并且被AppDelegate和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
    }


}

''

从你所说的,怀疑1)是正确的-你需要使用:

用法:

CalendarService.sharedInstance.doSomething()

如果没有您现有代码的具体示例,我真的说不出更多。

我认为您在面向对象编程方面犯了一个基本错误。在Calendars类中,您似乎已经封装了访问用户日历的所有代码。然后,您似乎得出了这样的结论:“这个代码需要可以从任何地方调用。因此,我的类的所有成员都需要是全局的(静态/类)。”

那是个错误。做这样的封装没有错;这的确是件好事。但是,使用封装的方法是使用helper实例。例如,假设您在一个视图控制器中(这很有可能)。然后它可以有一个属性:

let calendarHelper = Calendars()
现在,您的所有(或几乎所有)成员都可以(而且应该)成为实例成员。请记住,同一类型的实例各自独立地维护状态;这是它们封装的一部分。你会想要那种能力的


如果您认为需要静态/类成员的根本原因是在应用程序的生命周期中只需要一个EKEventStore实例,则将全局性/静态性向下推到该对象上(例如,通过“共享”EKEventStore和访问它的方法)让所有其他内容都成为普通的实例成员。

也许可以转到我猜你会因为“太宽泛”或“基于意见”而在这里被否决@Gereon:代码审查需要从具体项目中获得工作代码。以目前的形式,这个问题在CR上是离题的(缺少上下文)。可能有帮助:。感谢您的输入-在原始PostOk中添加了代码,因此您需要一个
静态var sharedInstance=Calendars()
(如上所述)来确保您有一个单身。然后,您可以遍历并删除
静态
/
前缀,例如,通过
Calendars.sharedInstance.yourPublicMethod()
将您需要公开的内容公开为
公共
。我建议将
Calendars
重命名为
CalendarService
,以明确这是处理创建/删除/编辑日历事件的唯一方法。为此,我还阅读了您提供的链接,它们也很好阅读。有关此模式的典型示例,请参阅我的。这里我们有一个类ManagerHolder,它对CLLocationManager的作用与您的类对EKEventStore的作用相同。看看视图控制器是如何合并这个类的一个实例的。matt-谢谢你-这是非常有洞察力的-我也可以看到这个主题如何进入基于灰色观点的领域-但是你的方法在这里似乎是明智的-我想很多新手程序员(我自己)他们面临着授权、依赖注入等学习模式的“艰巨”任务——这就是为什么我问我的问题:我想解决这些问题,因为这是真正学习的唯一途径。
let calendarHelper = Calendars()