<aside> 💡 위젯을 만들 때, 코어데이터에서 데이터를 어떻게 가져올까?

</aside>

⚠️ AppDelegate.persistance.context로 접근할 시 에러

Fetch data from CoreData

Fetch data from CoreData for iOS 14 widget

  1. Create App Group which will be used to create a Core Data Persistent Container

    1. App Group 추가시 (bug)로만 추가되고 릴리즈에는 없는데 빌드하거나 Xcode재시작하면 정상적으로 뜸 ( AppGroup(bug))

      <aside> ⚠️ Failed to create IXPlaceholder for app bundle ID

      </aside>

      시뮬레이터로 테스트시 해당 에러가 발생했는데, Xcode 종료 후 다시 빌드하면 정상 동작

    2. entitlements file 도 빌드하면 생성됨 (직접 추가하려고 해봤는데 해당 프로퍼티가 안나옴)

    The App Group entitlement gives us a container directory we can use to share data

    import Foundation
    
    public enum AppGroup: String {
        case facts = "group.com.hasensprung.Canvas"
        
        public var containerURL: URL {
            switch self {
            case .facts:
                return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: self.rawValue)!
            }
        }
    }
    
  2. Create your own CoreData stack

    1. 기존의 AppDelegate에서 정의했던 코어데이터관련 함수들을 싱글톤으로 새롭게 정의
    static let shared = CoreDataStack()
        
    private init() {}
    
    private let persistentContainer: NSPersistentContainer = {
        let storeURL = FileManager.appGroupContainerURL.appendingPathComponent("Canvas.sqlite")
        let container = NSPersistentContainer(name: "Canvas")
        
        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
        container.loadPersistentStores(completionHandler: { storeDescription, error in
            if let error = error as NSError? {
                print(error.localizedDescription)
            }
        })
        return container
    }()
    
    extension CoreDataStack {
        var managedObjectContext: NSManagedObjectContext {
            persistentContainer.viewContext
        }
    
        func saveContext() {
            managedObjectContext.performAndWait {
                if managedObjectContext.hasChanges {
                    do {
                        try managedObjectContext.save()
                    } catch {
                        print(error.localizedDescription)
                    }
                }
            }
        }
    }
    
  3. Set the container url to your custom shared container location

    extension FileManager {
        static let appGroupContainerURL = FileManager.default
            .containerURL(forSecurityApplicationGroupIdentifier: "AppGroupBundleID")!
    }
    
    let storeURL = FileManager.appGroupContainerURL.appendingPathComponent("Canvas.sqlite")
    

    GitHub - pawello2222/WidgetExamples: A demo project showcasing different types of Widgets created with SwiftUI and WidgetKit.

Update Widget Data When Main app enter background

Apple Developer Documentation

// SceneDelegate.swift in main-app

import WidgetKit

func sceneDidEnterBackground(_ scene: UIScene) {
    CoreDataStack.shared.saveContext()
    WidgetCenter.shared.reloadAllTimelines()
}

&ref

Fetch Data from CoreData | https://stackoverflow.com/questions/63936425/fetch-data-from-coredata-for-ios-14-widget

Create App Group | https://useyourloaf.com/blog/sharing-data-with-a-widget/

Assessing CoreData Stack in MVVM | https://stackoverflow.com/questions/61571960/accessing-core-data-stack-in-mvvm-application

Share between Main App and Widget | https://stackoverflow.com/questions/63922032/share-data-between-main-app-and-widget-in-swiftui-for-ios-14/63925053#63925053

Tutorial CoreData with SwiftUI | https://www.raywenderlich.com/9335365-core-data-with-swiftui-tutorial-getting-started