【Swift/Core Data】perform/performAndWaitの使い方!newBackgroundContext

【Swift/Core Data】perform/performAndWaitの使い方!newBackgroundContext

この記事からわかること

  • Swift/Core Dataperform/performAndWaitメソッド使い方
  • newBackgroundContext参照するときの注意
  • マルチスレッド対応

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

参考文献:公式リファレンス:Core Data プログラミングガイド〜Concurrency〜

環境

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

newBackgroundContextとは?

公式リファレンス:newBackgroundContext

func newBackgroundContext() -> NSManagedObjectContext

Core Dataでデータを操作する際に長時間かかる処理や大量のデータを処理する時などメインスレッドで実行したくない(UIをブロックしたくない)場合にはスレッドを分けて処理を実装することも多いと思います。しかしCore Dataはスレッドセーフではないためマルチスレッドでデータを扱う際には異なるスレッドから同一のContext(NSManagedObjectContext)を操作しないように注意が必要になります。Contextを異なるスレッドから参照しないようにする方法はいくつかあるようですがnewBackgroundContextメソッドもその1つです。

/// メインスレッドで使用するContext
private func makeContext() -> NSManagedObjectContext {
    let context = persistentContainer.viewContext
    context.automaticallyMergesChangesFromParent = true
    return context
}

/// バックグラウンドスレッドで使用するContext
private func makeBackgroundContext() -> NSManagedObjectContext {
    let context = persistentContainer.newBackgroundContext()
    context.automaticallyMergesChangesFromParent = true
    return context
}

newBackgroundContextメソッドはNSPersistentContainerの持つメソッドでバックグラウンドスレッド(プライベートキュー)用のContext(NSManagedObjectContext)を作成する役割を持っています。ここで生成されるContextはメインで使用しているContextとは別物なので、データを変更しても即座にメインのContextにマージされないため、適切なタイミングで明示的に変更を保存する必要があります。

またnewBackgroundContextで生成したContextからデータ取得や追加を行う際はperformまたはperformAndWaitブロックの中で操作する必要があるようです。

performメソッド

公式リファレンス:NSManagedObjectContext.performメソッド

func perform(_ block: @escaping () -> Void)

performNSManagedObjectContextが持つメソッドで指定されたコンテキストでブロック内の処理を実行する役割を持っています。非同期で処理を行い、指定されたコンテキストのスレッドで実行されます。

public func newEntity<T: NSManagedObject>(context: NSManagedObjectContext, completion: @escaping (T) -> Void) {
    context.perform {
        let entity = NSEntityDescription.entity(forEntityName: String(describing: T.self), in: context)!
        let newObject = T(entity: entity, insertInto: context)
        completion(newObject)
    }
}

performAndWaitメソッド

公式リファレンス:NSManagedObjectContext.performAndWaitメソッド

performAndWaitメソッドはperformと同じ役割を持っていますが、異なるのは同期的に実行される部分です。そのためブロック内の処理が完了するまで、現在のスレッドがブロックされるのでメインスレッドでの使用には注意が必要です。ただ利点として先ほど完了ハンドラーで受け取っていた結果を返り値として受け取ることができるようになります。

public func newEntity<T: NSManagedObject>(context: NSManagedObjectContext) -> T {
    var result: T!
    context.performAndWait {
        let entity = NSEntityDescription.entity(forEntityName: String(describing: T.self), in: context)!
        result = T(entity: entity, insertInto: context)
    }
    return result
}

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index