Swift

[Swift] CoreDataの変化をNotificationで監視する時ちょっとだけ楽する奴

CoreDataの変化をNotificationで監視するのは結構面倒臭い。
例えばこうなる。

普通にやるやつ

class Object: NSManagedObject {}

上のObjectに何か変化があった時何かするスケルトン

NotificatioCenter.default
    .addObserver(forName: .NSManagedObjectContextObjectsDidChange, object: managedObjectContext, queue: .main) { notification in

        guard let userInfo = notification.userInfo else {
            return
        }

        let inserted = userInfo[NSInsertedObjectsKey] as? Set<NSManagedObject>
        inserted
            .flatMap { $0 as? Object }
            .forEach {
                // do something
        }

        let updated = userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObject>
        updated
            .flatMap { $0 as? Object }
            .forEach {
                // do something
        }

        let deleted = userInfo[NSDeletedObjectsKey] as? Set<NSManagedObject>
        deleted
            .flatMap { $0 as? Object }
            .forEach {
                // do something
        }
}

ながい!!
スケルトンなのに超長い!!!

楽にするやつ

なので楽にするやつを作った。

extension Notification {

    struct ChangedType: OptionSet {

        let rawValue: UInt8

        static let inserted = ChangedType(rawValue: 0x0001)
        static let updated = ChangedType(rawValue: 0x0002)
        static let deleted = ChangedType(rawValue: 0x0004)

        static let all = ChangedType(rawValue: 0x0007)
    }

    func insertedManagedObjects<T: NSManagedObject>() -> [T] {

        return managedObjects(infoKey: NSInsertedObjectsKey)
    }

    func updatedManagedObjects<T: NSManagedObject>() -> [T] {

        return managedObjects(infoKey: NSUpdatedObjectsKey)
    }

    func deletedManagedObjects<T: NSManagedObject>() -> [T] {

        return managedObjects(infoKey: NSDeletedObjectsKey)
    }

    func changedManagedObjects<T: NSManagedObject>(type: ChangedType = .all) -> [T] {

        let inserted: [T] = type.contains(.inserted) ? insertedManagedObjects() : []
        let updated: [T] = type.contains(.updated) ? updatedManagedObjects() : []
        let deleted: [T] = type.contains(.deleted) ? deletedManagedObjects() : []

        return inserted + updated + deleted
    }

    private func managedObjects<T: NSManagedObject>(infoKey: String) -> [T] {

        guard let userInfo = self.userInfo as? [String: Any] else { return [] }

        let inserted = userInfo[infoKey] as? Set<NSManagedObject>
        return inserted?.flatMap({ $0 as? T }) ?? []
    }
}

これを使うとスケルトンはこうなる。

NotificatioCenter.default
    .addObserver(forName: .NSManagedObjectContextObjectsDidChange, object: managedObjectContext, queue: .main) { notification in

        notification
            .insertedManagedObjects()
            .forEach { (objcct: Object) in
                // do some
        }

        notification
            .updatedManagedObjects()
            .forEach { (objcct: Object) in
                // do some
        }

        notification
            .deletedManagedObjects()
            .forEach { (objcct: Object) in
                // do some
        }
}

ちょっとだけ短くなった。

がんばりましょう

型を確定するのが面倒くさい
もうちょっとどうにかしたい