2017-02-21 29 views
2

Я хотел бы использовать основные данные в сегодняшнем расширении. Я пробовал несколько способов вниз.Как использовать основные данные в расширении виджета сегодня?

  1. создать группу приложений и цель как для приложения, так и сегодня!

  2. создать CoreDataStack класс следующий this link

полный код здесь:

final class CoreDataStack { 
static let sharedStack = CoreDataStack() 
var errorHandler: (Error) -> Void = {_ in } 
//#1 
lazy var persistentContainer: NSPersistentContainer = { 
    let container = NSPersistentContainer(name: "spark") 
    container.loadPersistentStores(completionHandler: { [weak self](storeDescription, error) in 
     if let error = error { 
      NSLog("CoreData error \(error), \(error._userInfo)") 
      self?.errorHandler(error) 
     } 
    }) 
    return container 
}() 

//#2 
lazy var viewContext: NSManagedObjectContext = { 
    return self.persistentContainer.viewContext 
}() 

//#3 
// Optional 
lazy var backgroundContext: NSManagedObjectContext = { 
    return self.persistentContainer.newBackgroundContext() 
}() 

//#4 
func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
    self.viewContext.perform { 
     block(self.viewContext) 
    } 
} 

//#5 
func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
    self.persistentContainer.performBackgroundTask(block) 
} 



private init() { 
    //#1 
    NotificationCenter.default.addObserver(self, 
              selector: #selector(mainContextChanged(notification:)), 
              name: .NSManagedObjectContextDidSave, 
              object: self.managedObjectContext) 

    NotificationCenter.default.addObserver(self, 
              selector: #selector(bgContextChanged(notification:)), 
              name: .NSManagedObjectContextDidSave, 
              object: self.backgroundManagedObjectContext) 
} 

deinit { 
    NotificationCenter.default.removeObserver(self) 
} 

//#2 
lazy var libraryDirectory: NSURL = { 
    let urls = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask) 
    return urls[urls.count-1] as NSURL 
}() 

//#3 
lazy var managedObjectModel: NSManagedObjectModel = { 
    let modelURL = Bundle.main.url(forResource: "spark", withExtension: "momd")! 
    return NSManagedObjectModel(contentsOf: modelURL)! 
}() 

//#4 
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { 
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: 
     self.managedObjectModel) 
    let url = self.libraryDirectory.appendingPathComponent("spark.sqlite") 
    do { 
     try coordinator.addPersistentStore(ofType: 
      NSSQLiteStoreType, 
              configurationName: nil, 
              at: url, 
              options: [ 
              NSMigratePersistentStoresAutomaticallyOption: true, 
              NSInferMappingModelAutomaticallyOption: true 
      ] 
     ) 
    } catch { 
     // Report any error we got. 
     NSLog("CoreData error \(error), \(error._userInfo)") 
     self.errorHandler(error) 
    } 
    return coordinator 
}() 

//#5 
lazy var backgroundManagedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
    privateManagedObjectContext.persistentStoreCoordinator = coordinator 
    return privateManagedObjectContext 
}() 

//#6 
lazy var managedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) 
    mainManagedObjectContext.persistentStoreCoordinator = coordinator 
    return mainManagedObjectContext 
}() 

//#7 
@objc func mainContextChanged(notification: NSNotification) { 
    backgroundManagedObjectContext.perform { [unowned self] in 
     self.backgroundManagedObjectContext.mergeChanges(fromContextDidSave: notification as Notification) 
    } 
} 
@objc func bgContextChanged(notification: NSNotification) { 
    managedObjectContext.perform{ [unowned self] in 
     self.managedObjectContext.mergeChanges(fromContextDidSave: notification as Notification) 
    } 
} 
} 
struct CoreDataServiceConsts { 
static let applicationGroupIdentifier = "group.zz.zz.zz"//example 
} 

final class PersistentContainer: NSPersistentContainer { 
    internal override class func defaultDirectoryURL() -> URL { 
     var url = super.defaultDirectoryURL() 
     if let newURL = 
      FileManager.default.containerURL(
       forSecurityApplicationGroupIdentifier: CoreDataServiceConsts.applicationGroupIdentifier) { 
      url = newURL 
     } 
     return url 
    } 

я могу получить использование основных данных в расширении сегодня! но сущность пуста. И я проверял код, каждый тонкий, все в порядке. нет ошибки (потому что я сохраняю некоторые данные для теста, я отлично работаю.) Я действительно не знаю об этой проблеме. Это проблема с xcode?

+0

Включили ли вы классы Core Data в обе цели? (приложение и расширение) – Adolfo

+0

@Adolfo yup! Я могу проверить, как приложение и расширение в файле xcdatamodeld –

ответ

0

У вас нет подкласса NSPersistentContainer, чтобы иметь возможность установить каталог специализированного магазина.

class CoreDataStack { 
    public private(set) var persistentContainer: NSPersistentContainer 

    public init(withManagedObjectModelName momdName:String, sqliteStoreName storeName:String, storeBaseUrl baseUrl:URL?) { 
     guard let modelURL = Bundle(for: type(of: self)).url(forResource: momdName, withExtension:"momd") else { 
      fatalError("Error loading model from bundle") 
     } 

     guard let mom = NSManagedObjectModel(contentsOf: modelURL) else { 
      fatalError("Error initializing mom from: \(modelURL)") 
     } 

     persistentContainer = NSPersistentContainer(name: momdName, managedObjectModel: mom) 

     // If a base URL is given, use it. Else use persistent stores default 
     if let baseUrl = baseUrl { 
      var storeUrl = baseUrl.appendingPathComponent(momdName) 
      storeUrl = storeUrl.appendingPathExtension("sqlite") 
      let description = NSPersistentStoreDescription(url: storeUrl) 
      persistentContainer.persistentStoreDescriptions = [description] 
     } 

     persistentContainer.loadPersistentStores() { (storeDescription, error) in 
      if let error = error { 
        fatalError("Unresolved error \(error)") 
      } 
     } 
    } 

    // MARK: - ... save, get context and others ... 

} 

Instantiate его с помощью каталога App Группа:

guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupId) else { 
     fatalError("could not get shared app group directory.") 
    } 

let modelName = "Model" 
let storeName = "store" 

let myStore = CoreDataStack(withManagedObjectModelName: modelName, sqliteStoreName: storeName, storeBaseUrl: groupURL) 
+0

Спасибо за ваш ответ! Что такое имя магазина? Как я могу найти его? –

+0

Вы называете это (как константу). Он заканчивается как фактическое имя файла sqlite 'myStoreName.sqlite'. – shallowThought

+0

о! Понимаю. а затем Как мне позвонить сегодня в качестве класса расширения в качестве контекста? –

0

Попробуйте создать новый «Cocoa Touch Framework» и поместите файл xcdatamodeld и пользовательский класс управляемых объектов там, так что вы можете поделиться ими между приложение и расширение.

Затем подкласс NSPsistentContainer.

class SparkPersistentContainer: NSPersistentContainer = { 
    override class func defaultDirectoryURL() -> URL { 
    return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.your-app")! 

    init() { 
     let modelURL = Bundle(for: CustomManagedObject.self).url(forResource: "Spark", withExtension: "momd")! 
     let model = NSManagedObjectModel(contentsOf: modelURL)! 
     super.init(name: "Spark", managedObjectModel: model) 
    } 
}