I've developed an iOS framework several months ago, and now I would like to use CocoaPods to develop and distribute it easily. Now I distribute it sending my .framework file, I know this is not the best way and because of that I would like to use CocoaPods.
My problem is, inside my framework I use CoreData and I cannot make it work with Pods. If I get my old .framework and import it into my app project, everything works nice and CoreData works like a charm.
Digging into the issue, it seems that the Database.momd is not found into the bundle.
I'm going to attach the piece of code inside the framework that fails:
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle bundleWithIdentifier:@"kemmitorz.myFramework"] URLForResource:@"Database" withExtension:@"momd"];
// HERE modelURL RETURNS NIL with Pods
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
I know this could be caused by wrong framework configuration, or wrong Pods configuration, but I don't know what I'm missing.
Also, here is my myFramework.podspec file:
Pod::Spec.new do |s|
s.name = 'myFramework'
s.version = '0.1.0'
s.summary = 'A short description of myFramework.'
....
s.ios.deployment_target = '8.0'
s.source_files = 'myFramework/**/*.{h,m}'
s.frameworks = 'Foundation', 'Security', 'CFNetwork', 'CoreData'
s.library = 'icucore'
s.dependency 'SocketRocket'
s.dependency 'AFNetworking'
s.dependency 'OCMapper'
end
I've also tried to add {h,m,xcdatamodeld} to the type of source files unsuccessfully.
What I'm missing? Repeat, if I compile and import the framework on my own, everything works, so I suppose is something related with CocoaPods configuration.
It depends on the cocoapods version you are using, The recommended way to do it in 1.0.x is to add the s.resource_bundles
with a list of resource files that should be included in the bundle Cocoapods resource_bundles, for example:
...
s.source_files = 'myFramework/**/*.{h,m}'
s.resource_bundles = {'myFramework' => ['myFramework/*.xcdatamodeld']}
...
And then use some class of your framework to get the bundle and the resource:
guard let bundleURL = NSBundle(forClass: FrameworkClass.self).URLForResource("myFramework", withExtension: "bundle") else { throw Error }
guard let frameworkBundle = NSBundle(URL: bundleURL) else { throw Error }
guard let momURL = frameworkBundle.URLForResource("Database", withExtension: "momd") else { throw Error }
Things can get a little tricky here, but if you use the right paths everything works as expected.
A little update for swift 5 as I had been struggling to get this to work.
In the podspec I needed to define the s.resource_bundles as
s.resource_bundles = {
'FrameworkNameHere' => ['FrameworkNameHere/**/*.{xcdatamodeld}']
}
and in code to get the managed object model
guard let bundleUrl = Bundle(for: self).url(forResource: "FrameworkName", withExtension: "bundle"),
let frameworkBundle = Bundle(url: bundleUrl),
let modelUrl = frameworkBundle.url(forResource: "CoreDataModelName", withExtension: "momd"),
let managedObjectModel = NSManagedObjectModel(contentsOf: modelUrl) else {
fatalError("Managed object model not found")
}
Although this seems to be failing my unit tests that were originally built explicitly using the frameworks bundle id. I am thinking an initialiser for my core data class that allows me to do one or the other based on unit test/ app environment may be the answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With