如何拥有一个自己的东西成为NSManagedObject的子类的常规对象类?

时间:2018-12-15 05:27:20

标签: ios swift extension-methods

当前,我有两个不同的类,Alarm和AlarmMO,其中AlarmMO是NSManagedObject的子类。如果可能的话,我试图将两者合并为一个对象类,但遇到了一些麻烦。如何做到这一点的最佳方法?

这是我目前所拥有的,并且遇到各种错误:

class Alarm: NSManagedObject {

    //MARK: Properties
    @NSManaged var alarmTime: Double
    @NSManaged var alarmNumber: Int
    @NSManaged var startTimeInterval: Double
    @NSManaged var endTimeInterval: Double
    @NSManaged var note: String
    @NSManaged var notificationUuids: [String]
    @NSManaged var recurrenceIndex: Int
    var recurrence: RecurrenceOptions = .today
    let NUMBER_OF_ALLOWED_NOTIFICATIONS_CREATED_AT_ONE_TIME = 10

}

extension Alarm {

convenience init?(alarmNumber: Int, timeIntervals: TimeIntervals, note: String, recurrence: RecurrenceOptions) {

    self.alarmNumber = alarmNumber
    self.note = note
    self.recurrence = recurrence
    self.notificationUuids = [String]()

    let date = Date()
    let calendar = Calendar.current
    let currentDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: date)
    var dateComponents = DateComponents()
    dateComponents.year = currentDateComponents.year
    dateComponents.month = currentDateComponents.month
    dateComponents.timeZone = currentDateComponents.timeZone
    dateComponents.day = currentDateComponents.day

    let startInterval = Alarm.convertToTimeDouble(hour: timeIntervals.hourStartInterval, minute: timeIntervals.minuteStartInterval)
    let endInterval = Alarm.convertToTimeDouble(hour: timeIntervals.hourEndInterval, minute: timeIntervals.minuteEndInterval)
    self.startTimeInterval = startInterval
    self.endTimeInterval = endInterval
    if endInterval < startInterval {
        os_log("Error: Alarm time endInterval is before startInterval", log: OSLog.default, type: .info)
        return nil
    }
    self.alarmTime = Double.random(in: startInterval ... endInterval)

    let hour = Alarm.extractHourFromTimeDouble(alarmTimeDouble: self.alarmTime)
    let minute = Alarm.extractMinuteFromTimeDouble(alarmTimeDouble: self.alarmTime)
    os_log("Attempting to create alarm with time %d:%02d", log: OSLog.default, type: .info, hour, minute)

    createNotifications(dateComponents: dateComponents)

}

public static func convertToTimeDouble(hour: Int, minute: Int) -> Double {

    return Double(hour) + (Double(minute) / 60.0)

}

public static func extractHourFromTimeDouble(alarmTimeDouble: Double) -> Int {

    return Int(floor(alarmTimeDouble))

}

public static func extractMinuteFromTimeDouble(alarmTimeDouble: Double) -> Int {

    return Int(round((alarmTimeDouble - floor(alarmTimeDouble)) * 60))

}

func createNotifications(dateComponents: DateComponents) {

    switch (self.recurrence) {
    case .today:
        self.createNotification(for: dateComponents)
    case .tomorrow:
        self.createNotification(for: self.day(after: dateComponents))
    case .daily:
        var numberOfCreatedNotifications = 0
        var currentDay: DateComponents? = dateComponents
        while numberOfCreatedNotifications < self.NUMBER_OF_ALLOWED_NOTIFICATIONS_CREATED_AT_ONE_TIME {
            self.createNotification(for: currentDay)
            currentDay = self.day(after: currentDay)
            numberOfCreatedNotifications += 1
        }
    }

}

//MARK: Private functions

private func createNotification(for dateComponents: DateComponents?) {

    let center = UNUserNotificationCenter.current()

    let content = UNMutableNotificationContent()
    content.title = "Random Alarm"
    content.subtitle = "It's time!"
    content.body = self.note
    content.sound = UNNotificationSound.default

    guard let dateComponents = dateComponents else {
        os_log("Could not unwrap dateComponents in createNotification() in Alarm.swift", log: OSLog.default, type: .debug)
        return
    }
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)

    let uuidString = UUID().uuidString
    let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
    self.notificationUuids.append(uuidString)

    guard let day = dateComponents.day else {
        os_log("Could not unwrap dateComponents.day in createNotification() in Alarm.swift", log: OSLog.default, type: .debug)
        return
    }
    guard let hour = dateComponents.hour else {
        os_log("Could not unwrap dateComponents.hour in createNotification() in Alarm.swift", log: OSLog.default, type: .debug)
        return
    }
    guard let minute = dateComponents.minute else {
        os_log("Could not unwrap dateComponents.minute in createNotification() in Alarm.swift", log: OSLog.default, type: .debug)
        return
    }
    os_log("Creating notification for day: %d, time: %d:%02d, with uuid=%s", log: OSLog.default, type: .debug, day, hour, minute, uuidString)

    center.add(request) { (error) in
        if let err = error {
            print("error \(err.localizedDescription)")
        }
    }
}

private func day(after dateComponents: DateComponents?) -> DateComponents? {

    let calendar = Calendar.autoupdatingCurrent

    guard let dateComponents = dateComponents,
        let date = calendar.date(from: dateComponents),
        let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
        else {
            os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
            return nil
    }
    let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
    return newDateComponents

}

}

1 个答案:

答案 0 :(得分:1)

如果AlarmMO是您在Core Data中的实体,则应为您创建AlarmMO对象。您可以使用扩展程序添加所需的其他任何行为。

虽然您可以创建一个新的初始化程序,但我可能会使用一种使用静态函数的工厂方法:

extension AlarmMO {

    static func newAlarm(context: NSManagedObjectContext, alarmNumber: Int, timeIntervals: TimeIntervals, note: String, recurrence: RecurrenceOptions) -> AlarmMO? {

        let startInterval = Alarm.convertToTimeDouble(hour: timeIntervals.hourStartInterval, minute: timeIntervals.minuteStartInterval)
        let endInterval = Alarm.convertToTimeDouble(hour: timeIntervals.hourEndInterval, minute: timeIntervals.minuteEndInterval)

        if endInterval < startInterval {
            os_log("Error: Alarm time endInterval is before startInterval", log: OSLog.default, type: .info)
            return nil
        }
        let newAlarm = AlarmMO(context: context)
        newAlarm.alarmNumber = alarmNumber
        newAlarm.note = note
        newAlarm.recurrence = recurrence
        newAlarm.notificationUuids = [String]()
        newAlarm.alarmTime = Double.random(in: startInterval ... endInterval)
        newAlarm.startTimeInterval = startInterval
        newAlarm.endTimeInterval = endInterval

        return newAlarm
    }

    var recurrence: RecurrenceOptions {
        get {
            return RecurrenceOptions(rawValue: self.recurrenceIndex)!
        }

        set {
            self.recurrenceIndex = newValue.rawValue
        }
    }

    var hour: Int {
        return Int(floor(self.alarmTime))
    }

    var minute: Int {
        return Int(round((self.alarmTime - floor(self.alarmTime)) * 60))
    }

    func scheduleNotification() {
        os_log("Attempting to create alarm with time %d:%02d", log: OSLog.default, type: .info, self.hour, self.minute)
        let date = Date()
        let calendar = Calendar.current
        let currentDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: date)
        var dateComponents = DateComponents()
        dateComponents.year = currentDateComponents.year
        dateComponents.month = currentDateComponents.month
        dateComponents.timeZone = currentDateComponents.timeZone
        dateComponents.day = currentDateComponents.day
        createNotifications(dateComponents: dateComponents)
    }


    // Note:  This probably should be in TimeIntervals, rather than here
    public static func convertToTimeDouble(hour: Int, minute: Int) -> Double {
        return Double(hour) + (Double(minute) / 60.0)
    }

}