2016-10-02 8 views
4

カスタムstore.sqlite URLをNSPersistentContainerに設定するにはどうすればよいですか?NSPersistentContainerのカスタムストアURLを設定する方法

私はNSPersistentContainerをサブクラス化、醜い方法を発見した:

final public class PersistentContainer: NSPersistentContainer { 
private static var customUrl: URL? 

public init(name: String, managedObjectModel model: NSManagedObjectModel, customStoreDirectory baseUrl:URL?) { 
    super.init(name: name, managedObjectModel: model) 
    PersistentContainer.customUrl = baseUrl 
} 

override public class func defaultDirectoryURL() -> URL { 
    return (customUrl != nil) ? customUrl! : super.defaultDirectoryURL() 
} 

}

良い方法はありますか?

背景:App Groupsの共有ディレクトリに保存する必要があります。

答えて

8

NSPersistentStoreDescriptionクラスでこれを行います。永続ストアファイルをどこに置くべきかを示すファイルURLを提供するために使用できるイニシャライザがあります。

let description = NSPersistentStoreDescription(url: myURL) 

はその後、このカスタムの場所を使用するように指示する NSPersistentContainer年代 persistentStoreDescriptions属性を使用します。

container.persistentStoreDescriptions = [description] 

注:それはまだ存在しない場合でもmyURLは、完全な/path/to/model.sqliteを提供する必要があります。親ディレクトリのみを設定することはできません。あなたはどのような目的のためにNSPersistentStoreDescriptionを使用する場合

+0

これは、CoreDataスタックを初期化するときではなく、store.sqliteがすでに存在する場合にのみ機能します。 – shallowThought

+0

いいえ、ファイルが存在しない場合は正常に動作します。しかし、ファイルを移動するディレクトリが存在していなければならず、アプリケーショングループを正しく設定する必要があります。ただし、ストアファイルが既に存在する必要はありません。 –

+0

奇妙な。ここでは、 "ファイルが見つかりません"というエラーが発生してクラッシュします。ファイルが既に存在する場合はうまく動作します。 – shallowThought

4

トムの答えを拡張し、あなたがその記述に基づいて基本的な初期化子NSPersistentStoreDescription()loadPersistentStores()を使用している場合、それは既存の永続ストアを上書きし、すべてになるので、私の経験でNSPersistentStoreDescription(url:)でinitをするようにしてください次回のビルド時と実行時のデータです。ここで私はURLと説明を設定するために使用するコードは次のとおりです。

let container = NSPersistentContainer(name: "MyApp") 

let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! 
let url = storeDirectory.appendingPathComponent("MyApp.sqlite") 
let description = NSPersistentStoreDescription(url: url) 
description.shouldInferMappingModelAutomatically = true 
description.shouldMigrateStoreAutomatically = true 
container.persistentStoreDescriptions = [description] 

container.loadPersistentStores { (storeDescription, error) in 
    if let error = error as? NSError { 
     print("Unresolved error: \(error), \(error.userInfo)") 
    } 
} 
1

私はちょうどPersistentContainerによって作成されたDBの場所がUIManagedDocumentによって作成されたDBから異なっていることを知ります。ここでUIManagedDocumentによるDBの場所のスナップショットです:

enter image description here

は、次のコードは、DBを作成するために使用されています

let fileURL = db.fileURL // url to ".../Documents/defaultDatabase" 
let fileExist = FileManager.default.fileExists(atPath: fileURL.path) 
if fileExist { 
    let state = db.documentState 
    if state.contains(UIDocumentState.closed) { 
     db.open() 
    } 
} else { 
    // Create database 
    db.save(to: fileURL, for:.forCreating) 
} 

それはPersistentContainerで呼ばデシベルが実際のファイルであることのように見えますさらに「StoreContent」フォルダの下に「persistentStore」と表示されます

これは、私の場合のdb「defaultDatabase」がPersistentContainerで作成できない理由を説明してくれますカスタマイズされたdbファイルを指定するか、フォルダが既に存在するためクラッシュする可能性があります。ここで

let url = db.fileURL.appendingPathComponent("MyDb.sqlite") 
let storeDesription = NSPersistentStoreDescription(url: url) 
container.persistentStoreDescriptions = [storeDesription] 
print("store description \(container.persistentStoreDescriptions)" 
// store description [<NSPersistentStoreDescription: 0x60000005cc50> (type: SQLite, url: file:///Users/.../Documents/defaultDatabase/MyDb.sqlite) 
container.loadPersistentStores() { ... } 

が新しいMyDb.sqliteです::上記の分析に基づいて

enter image description here

、あなたが持っている場合、私は、さらに次のようにファイル名「MyDb.sqlite」を付加することによって、これを検証しましたこのようなコードは:

if #available(iOS 10.0, *) { 
    // load db by using PersistentContainer 
    ... 
} else { 
    // Fallback on UIManagedDocument method to load db 
    ... 
} 

ユーザーのデバイスは、10.0前と後で10+に更新されるiOSの上にあってもよいです。今回の変更では、クラッシュや新しい(空の)データベース(データの消失)の作成を避けるために、URLを調整する必要があります。

関連する問題