CoreDataフレームワークを多用する静的ライブラリを構築しました。外部プロジェクトでライブラリを正常に使用できますが、メインプロジェクトに.xcdatamodelファイルを含めた場合に限ります。ライブラリの目的は実装の詳細を可能な限り隠すことだったので、これは理想的とは言えません。
別の 質問 で、リソースをライブラリにバンドルできないと通知されました(これは今では完全に理にかなっています)。
それで、メインプロジェクトにモデルを含めることなく、プログラムでモデルを「発見」できるようにする方法はありますか?
また、CoreDataを使用する独自の静的ライブラリを作成しました。静的ライブラリに加えて、プロジェクトに別のバンドルターゲットがあり、バンドルリソースのコピーアイテムがあります。これは、いくつかの画像などをバンドルにコピーし、ソースのコンパイルフェーズでxcdatamodelをコンパイルします。
最終的なバンドルには、必要なすべてのファイルが含まれます。静的ライブラリに依存するメインプロジェクトでは、そのバンドルも含める必要があります。これで、メインプロジェクトはコアデータを使用するために必要なmomファイルにアクセスできるようになります。
バンドルのmomでコアデータを使用するには、コードでマージされた管理対象オブジェクトモデルを作成する必要があります(メインプロジェクトにもコアデータモデルがある可能性があります)。
- (NSManagedObjectModel *) mergedManagedObjectModel
{
if (!mergedManagedObjectModel)
{
NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease];
[allBundles addObjectsFromArray: [NSBundle allBundles]];
[allBundles addObjectsFromArray: [NSBundle allFrameworks]];
mergedManagedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]] retain];
}
return mergedManagedObjectModel;
}
バンドルを含めるだけで、xcdatamodelを提供する必要はなく、コンパイルされたmomファイルのみを含める必要があります。
Saschaの答えは私を正しい軌道に乗せました。コンパイルされた.mom
ファイルを静的ライブラリから.mom
ファイルにホストプロジェクトからマージするのは比較的簡単でした。簡単な例を次に示します。
MyStaticLibrary
という名前の新しいXCode静的ライブラリプロジェクトを作成します
MyStaticLibraryModels.xcdatamodel
という名前の.xcdatamodelファイルをMyStaticLibrary
に作成し、いくつかのEntity
sを追加してから、ヘッダーと実装を生成します。 MyStaticLibrary
ターゲットをビルドすると、libMyStaticLibrary.a
バイナリファイルが生成されますが、コンパイルされた.mom
ファイルは含まれません。そのためには、バンドルを作成する必要があります。
Loadable Bundle
の下にあるタイプMacOS X > Cocoa
の新しいビルドターゲットを作成し、新しいターゲットMyStaticLibraryModels
を呼び出しましょう。
MyStaticLibraryModels.xcdatamodel
をMyStaticLibraryModels
ターゲットのCompile Sources
ビルドフェーズにドラッグします。 MyStaticLibraryModels
ターゲットをビルドすると、MyStaticLibraryModels.bundle
というファイルが生成され、コンパイルされたNSManagedObjectModel
ファイルMyStaticLibraryModels.mom
が含まれます。
MyStaticLibrary
ターゲットとMyStaticLibraryModels
ターゲットの両方をビルドした後、libMyStaticLibrary.a
(および関連するModelヘッダーファイル)とMyStaticLibraryModels.bundle
をホストプロジェクトMyAwesomeApp
にドラッグします。
MyAwesomeApp
はCoreData
を使用し、独自の.xcdatamodel
ファイルを持っており、独自のビルドプロセス中に.momファイルにコンパイルされます。この.mom
ファイルをMyStaticLibraryModels.bundle
にインポートしたファイルとマージします。 MyAwesomeApp
プロジェクトのどこかに、MyAwesomeApp
sNSManagedObjectModel
を返すメソッドがあります。このメソッド用に生成されたAppleテンプレートは次のようになります:
.。
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
これを変更して、NSManagedObjectModel
s、MyAwesomApp
s、およびMyStaticLibraryModels
の両方を、次のように1つの結合されたNSManagedObjectModel
としてマージして返します。
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSMutableArray *allManagedObjectModels = [[NSMutableArray alloc] init];
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"];
NSManagedObjectModel *projectManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
[allManagedObjectModels addObject:projectManagedObjectModel];
[projectManagedObjectModel release];
NSString *staticLibraryBundlePath = [[NSBundle mainBundle] pathForResource:@"MyStaticLibraryModels" ofType:@"bundle"];
NSURL *staticLibraryMOMURL = [[NSBundle bundleWithPath:staticLibraryBundlePath] URLForResource:@"MyStaticLibraryModels" withExtension:@"mom"];
NSManagedObjectModel *staticLibraryMOM = [[NSManagedObjectModel alloc] initWithContentsOfURL:staticLibraryMOMURL];
[allManagedObjectModels addObject:staticLibraryMOM];
[staticLibraryMOM release];
managedObjectModel_ = [NSManagedObjectModel modelByMergingModels:allManagedObjectModels];
[allManagedObjectModels release];
return managedObjectModel_;
}
これにより、NSManagedObjectModel
とEntity
の両方からMyAwesomeApp
とマージされたMyStaticLibrary
が返されます。
Sascha Konietzkeのソリューションはうまく機能しますが、機能するために提供する必要のある重要な警告が1つあります。モデルを含むバンドルを最初にロードする必要があります。そうしないと、モデルは配列に含まれず、MOMにマージされません。
彼の場合、彼はおそらくすでにバンドルからリソースにアクセスしているため、このコードが実行される前にバンドルがすでにロードされています。
いいえ、iPhoneアプリでApple以外のフレームワークを使用する際の制限により、OS Xと比較して依存関係ゲームが実際に変わります。ほとんどのiPhoneの「フレームワーク」(Mac用のGoogleのツールボックス、Core Plotなど)は実際には推奨 =製品(つまり静的ライブラリ)をリンクするのではなく、メインアプリケーションプロジェクトにソースを含めること。コミュニティのコンセンサスは、iPhoneでは、フレームワークの利用者がライブラリを使用するために少し「手動」の作業をしなければならないと予想しても問題ないと思います。あなたの場合、これはメインプロジェクトにxcdatamodelファイルを含めています。ほとんどのObjective-Cと同様に、実装の詳細を使用しないようにユーザーに指示し、そのままにしておきます。
Prairiedoggの答えは少し時代遅れです。Xcode5でこれを行うためのチュートリアルは次のとおりです。 http://bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static -ライブラリ/
coreDataを含むライブラリもあります。埋め込みリソースを使用してフレームワークを管理するためのこのテンプレートを見つけました
新しいプロジェクトで使用するのは本当に簡単です(既存のプロジェクトに適用するのはもっと難しいです)が、framewoksビルドの場合は本当にクールです:-)
Xcdatamodel/momファイルを使用する代わりに、コードでモデルを作成することもできます(特に単純なモデルがある場合)。この方法では、リソースの追加バンドルを作成する必要はありません。これは、2つの属性を含む1つのテーブルを持つ簡単な例です。
- (NSManagedObjectModel *)coreDataModel
{
NSManagedObjectModel *model = [NSManagedObjectModel new];
NSEntityDescription *eventEntity = [NSEntityDescription new];
eventEntity.name = @"EventEntity";
eventEntity.managedObjectClassName = @"EventEntity";
NSAttributeDescription *dateAttribute = [NSAttributeDescription new];
dateAttribute.name = @"date";
dateAttribute.attributeType = NSDateAttributeType;
dateAttribute.optional = NO;
NSAttributeDescription *typeAttribute = [NSAttributeDescription new];
typeAttribute.name = @"type";
typeAttribute.attributeType = NSStringAttributeType;
typeAttribute.optional = NO;
eventEntity.properties = @[dateAttribute, typeAttribute];
model.entities = @[eventEntity];
return model;
}
コードからモデルを作成する方法についてのチュートリアルは次のとおりです。 https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/
また、このアプローチに基づいて、 LSMiniDB と呼ばれる、ニーズに合う可能性のある小さくて使いやすいライブラリを作成したので、それも確認できます。
また、私の場合、NSManagedObjectのプロパティを使用しているときに、コンソールで「警告:動的アクセサーが@property実装を見つけられませんでした...」などの警告がありました。サブクラス。これらのプロパティを別のファイルのカテゴリに含めるのではなく、クラスインターフェイス/実装に移動することで、これを修正できました(現在、xcodeはデフォルトで、このコードを別のファイルClassName + CoreDataClassとClassName + CoreDataPropertiesに分割して生成しています。および各サブクラスのカテゴリ)。
Saschaの答えのためのSwift2バージョン:
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
var allBundles = NSMutableSet()
allBundles.addObjectsFromArray(NSBundle.allBundles())
allBundles.addObjectsFromArray(NSBundle.allFrameworks())
let model = NSManagedObjectModel.mergedModelFromBundles(allBundles.allObjects as? [NSBundle])
return model!
}()