我有一个从事件存储中检索到的日历项(模型(的类。我还没有为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()
没有您现有代码的特定示例,我不能说更多。