How be notified only when CoreData object(s) change? - ios

Each time I synchronise with my server, I refresh all fields of my CoreData objects.
Even if nothing changes I still receive NSManagedObjectContextObjectsDidChangeNotification elsewhere in my code.
Is this expected behaviour?
How can I prevent this and only be notified when something has actually changed?
When I add below code after refreshing an object, things work as I want. But why can't CoreData sort this out?
if (object.changedValues.count == 0)
{
[object.managedObjectContext refreshObject:object mergeChanges:NO];
}

Yes, even though values aren't changing new writes are still happening in Managed Object Context. So, NSManagedObjectContextObjectsDidChangeNotification are expected to be fired.
Consider using a NSFetchedResultsController as:
#interface CoreDataHelper : NSObject < NSFetchedResultsControllerDelegate >
#property (nonatomic, readonly) NSManagedObjectContext *context;
+ (instancetype)sharedInstance;
#end
#implementation
#synthesize context = _context;
+ (instancetype)sharedInstance{
static dispatch_once_t once;
static CoreDataHelper *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
- (NSManagedObjectContext *)context{
if (_context != nil) {
return _context;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; // you know what goes in PSC here, right?
if (!coordinator) {
NSLOG(#"Argh! coordinator == nil");
return nil;
}
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_context setPersistentStoreCoordinator:coordinator];
return _context;
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{
/*
This function will be invoked by the OS whenever a Managed Object changes.
Keep in mind that this will be invoked on the Managed Object Context Queue.
This is the place where your logic to be performed whenever a object changes needs to be.
*/
}
#end
// Now in your file
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[CoreDataHelper sharedInstance].context sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = [CoreDataHelper sharedInstance];
NSError *error;
if (![fetchedResultsController performFetch:&error]){
NSLOG(#"fetch error %#", error);
}
Now, since we have hooked up self as delegate of fetchedResultsController, self needs to conform to the NSFetchedResultsControllerDelegate protocol.
You choose to override any of the optional methods, most straight-forward being:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

Related

Coredata Fetched Results Controller save with child NSPrivateQueueConcurrencyType context

I have UICollectionViewController with <NSFetchedResultsControllerDelegate> and CoreData Singleton manager. So when I trying to update some Title of my object I see error.
CollectionViewController.m
#interface CollectionViewController ()<NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext* managedObjectContext;
#implementation CollectionViewController
- (NSManagedObjectContext*) managedObjectContext {
if (!_managedObjectContext) {
_managedObjectContext = [[CoreDataManager sharedManager] managedObjectContext];
}
return _managedObjectContext;
}
-(void)pushTheButton: (UIButton*) sender{
NSIndexPath *indexPath = [self.collectionView indexPathForCell:(PKMapObjectCVCell *)sender.superview.superview];
SomeObjectClass* object = [self.fetchedResultsController objectAtIndexPath:indexPath];
[[CoreDataManager sharedManager] changeValueForObject: object.objectID];
}
CoreDataManager.m
#implementation CoreDataManager
#synthesize mainPrivateManagedObjectContext = _mainPrivateManagedObjectContext;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+(CoreDataManager*) sharedManager{
static CoreDataManager* manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CoreDataManager alloc] init];
});
return manager;
}
- (void) changeValueForObject:(NSManagedObjectID*) myobjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
SomeObjectClass * editableObject = [bgcontext objectWithID:myObjectID];
editableObject.title = #"New Title";
// [bgcontext updatedObjects];
[self saveContextForBGTask:bgcontext];
}
- (void)saveContextForBGTask:(NSManagedObjectContext *)bgTaskContext {
if (bgTaskContext.hasChanges) {
[bgTaskContext performBlockAndWait:^{ //error on this line:
[error] error: Serious application error. Exception was caught during
Core Data change processing. This is usually a bug within an observer
of NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) CoreData: error: Serious application error.
Exception was caught during Core Data change processing. This is
usually a bug within an observer of
NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) 2018-03-21 17:07:42.644646+0400
AppName[17860:3506816] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: 'The left hand side
for an ALL or ANY operator must be either an NSArray or an NSSet.
NSError *error = nil;
[bgTaskContext save:&error];
}];
[self saveDefaultContext:YES]; // Save default context
}
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
_mainPrivateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_mainPrivateManagedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:_mainPrivateManagedObjectContext];
return _managedObjectContext;
}
- (NSManagedObjectContext *)getContextForBGTask {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:_managedObjectContext];
return context;
}
So, what I am doing wrong?
code delete object, is working fine:
- (void) switchObjectLike:(NSManagedObjectID*) mapObjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
PKMapObj * mapObject = [bgcontext objectWithID:mapObjectID];
[bgcontext deleteObject:mapObject];
[self saveContextForBGTask:bgcontext];
}
So, problem was with predicate in NSFetchedResultsController. When some content was updated, NSFetchedResultsController preparing to reload collection view, and before call this method:
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
it was crashed, but never shown error with it. Thanks everybody!

Getting and using NSManagedObject in different threads

I have problem with architecting my code.
I have view that create and depend on model class. Model class is responsible for all calculations and logic. This mean that it has a lot of things to calculate, and getting object from Core data.
Regarding enter link description here, every NSManagedObject that is obtained in one thread, need to be used in same thread.
My problem is that on create object need to be obtained in different thread, because it take some time to build model, but after this, I need to obtain object and they properties in main thread from View (for example in cellForIndex...)
I know, I am not the only one with this design. How others solve this problem?
EDIT :
To concrete this with code.
Let say we have UIView object MyUIView and model object Model
MyUIView
#interface MyUIView ()
#property(nonatomic) Model * model;
#end
#implementation MyUIView
- (void) createModel
{
// privateManagerContext is context manager created with
// NSPrivateQueueConcurrencyType, connected to persistent store
// and sync with "main thread" manager context with
// NSManagedObjectContextDidSaveNotification and NSManagedObjectContextDidSaveNotification
[self.model createWithManagadContext:privateManagerContext];
}
// ASSUME THAT THIS CODE IS CALLED AFTER
- (void) getNumberOfSomeProperties
{
int number = [self.model getNumberOfProperties];
}
- (void) getProperties
{
NSArray *array = [self.model properties]
}
// OR WE HAVE TO TRIGGERED SOME LONG CALCULATION
- (void) triggerLongCalculation
{
[self.model longCalculation];
}
- (void) afterNotifyModelIsCompletedCalculating
{
[self doSomeWork];
[self getProperties];
....
}
#end
Model
#interface Model ()
#property(nonatomic) NSArray * cashedProperties;
#end
#implementation MyUIView
- (void) createWithManagadContext:(NSManagedObjectContext *) privateManagerContext
{
dispatch_async(self.model_queue, ^(void){
// Here we fetch objects and do some calculations
[self populateModel];
/// Model is complete
[Notifications notifyModelIsCompletedCreating:self];
});
}
- (void) longCalculation
{
dispatch_async(self.model_queue, ^(void){
// NO CORE DATA FETCH INVOLVED
[Notifications notifyModelIsCompletedCalculating:self];
});
}
- (int) getNumberOfProperties
{
return self.cashedProperties.count;
}
- (NSArray) properties
{
NSMutableArray * a = [[NSMutableArray alloc]init];
for (Property * p in self.cashedProperties) {
[a addObject:p.name];
}
return a;
}
#end
So in this hypothetical classes, how would you handle all NSManagedObject and NSManagedObjectContext ?
EDIT 2 :
I am using pattern where I create two managed object context in appdelegate, one private and one main, and create sync between them.
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
- (NSManagedObjectContext * ) privateQueueContext
{
if (_privateQueueContext != nil) {
return _privateQueueContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateQueueContext setPersistentStoreCoordinator:coordinator];
}
return _privateQueueContext;
}
- (id)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(contextDidSavePrivateQueueContext:)
name:NSManagedObjectContextDidSaveNotification
object:[self privateQueueContext]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(contextDidSaveMainQueueContext:)
name:NSManagedObjectContextDidSaveNotification
object:[self managedObjectContext]];
}
return self;
}
#pragma mark - Notifications
- (void)contextDidSavePrivateQueueContext:(NSNotification *)notification
{
#synchronized(self) {
[self.managedObjectContext performBlock:^{
NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey];
for (NSManagedObject* obj in objects) {
NSManagedObject* mainThreadObject = [self.managedObjectContext objectWithID:obj.objectID];
[mainThreadObject willAccessValueForKey:nil];
}
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
}
- (void)contextDidSaveMainQueueContext:(NSNotification *)notification
{
#synchronized(self) {
[self.privateQueueContext performBlock:^{
NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey];
for (NSManagedObject* obj in objects) {
NSManagedObject* mainThreadObject = [self.privateQueueContext objectWithID:obj.objectID];
[mainThreadObject willAccessValueForKey:nil];
}
[self.privateQueueContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
}
You could use two different NSManagedObjectContext with parent/child configuration. The parent for the UI, in the main queue, the child for heavy work in the private queue. Once the child context finishes to perform his heavy work would save, its changes are then propagated to the main context. You could use in the case you're using a table view in your view controller a NSFetchedResultsController that observe on the main context. Once the main context receives and merge the changes from his child context, the NSFetchedResultsController would update the UI accordingly, as long as its delegate methods are implemented.
If you don't use NSFRC you could register your main context for notifications "name:NSManagedObjectContextObjectsDidChangeNotification" or "name:NSManagedObjectContextObjectsDidSaveNotification" and see what objects have been added/deleted/updated and update the UI consequently.
If you use thread confinement instead (made obsolete by Apple in the last years) of parent/child you may want to pass the objectID between threads and fetch the object in the context you need it as NSManagedObjects are not thread-safe.
Code:
First I wouldn't have a reference of your model in the view. View should be just dumb and expose outlets or methods to be populated. I would have a ViewController communicating with the model and the view.
Lets say you have a util method to create a worker context (as child context of your parent in the main queue) every time you need to perform a heavy job.
func newWorkerContext() -> NSManagedObjectContext {
let workerContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
workerContext.parentContext = self.mainContext
return workerContext
}
In your model you would have
//Lets say you have a reference to your workerContext
func longCalculation() {
workerContext.performBlock({ () -> Void in
//Heavy process of information
//Once finished you save the worker context and changes are propagated to the parent context
})
}
In your ViewController you would have
class MyViewController: UIViewController {
func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(handleDataModelChange(_:)), name: NSManagedObjectContextObjectsDidChangeNotification, object: REFERENCE_TO_MAIN_CONTEXT)
}
func deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: NSManagedObjectContextObjectsDidChangeNotification, object: REFERENCE_TO_MAIN_CONTEXT)
}
func handleDataModelChange(notification: NSNotification) {
//Check changes are relevant for the UI you are updating and if so update.
if let changedObjects = changes[NSUpdatedObjectsKey] as? NSSet {
}
if let insertedObjects = changes[NSInsertedObjectsKey] as? NSSet {
}
if let deletedObjects = changes[NSDeletedObjectsKey] as? NSSet {
}
}
}
Remember that to persist the changes in the persistence store you have to save on the main context.
It's a simple example but I hoped it gives you the idea on what to do now.

Multithreading violation core data

I have an app where I download the data on startup using a list of operations and it crashes randomly for unknown core data reasons so I spent few days on checking the best practices to update/fetch data in multithreading core data with MagicalRecord. One of the options was to enable the multithreading debugger -com.apple.CoreData.ConcurrencyDebug 1 where Xcode stops the apps when it violates one of their rules. So, Xcode stops my app on this line [SyncRequestEntity MR_createEntityInContext:[self getPrivateContext]]
+ (MagicalRecordVersionNumber) version
{
return MagicalRecordVersionNumber2_3;
}
#implementation NSManagedObjectContext (MagicalRecord)
+ (NSManagedObjectContext *) MR_context
{
return [self MR_contextWithParent:[self MR_rootSavingContext]];
}
+ (NSManagedObjectContext *) MR_contextWithParent:(NSManagedObjectContext *)parentContext
{
NSManagedObjectContext *context = [self MR_newPrivateQueueContext];
[context setParentContext:parentContext];
[context MR_obtainPermanentIDsBeforeSaving];
return context;
}
- (void) MR_obtainPermanentIDsBeforeSaving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(MR_contextWillSave:)
name:NSManagedObjectContextWillSaveNotification
object:self];
}
+ (NSManagedObjectContext *) MR_newPrivateQueueContext
{
NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
MRLogInfo(#"Created new private queue context: %#", context);
return context;
}
#end
#implementation MyClass
- (NSManagedObjectContext *) getPrivateContext
{
if (self.privateContext == nil)
{
self.privateContext = [NSManagedObjectContext MR_context];
}
return self.privateContext;
}
- (SyncRequestEntity *) getSyncRequest
{
SyncRequestEntity *syncRequest = [SyncRequestEntity MR_findFirstByAttribute:#"key" withValue:self.itemKey inContext:[self getPrivateContext]];
// Checking if the entity was sync previously with the same filters.
if (syncRequest == nil)
{
syncRequest = [SyncRequestEntity MR_createEntityInContext: [self getPrivateContext]];
}
return syncRequest;
}
#end
#implementation NSManagedObject (MagicalRecord)
+ (id) MR_createEntityInContext:(NSManagedObjectContext *)context
{
if ([self respondsToSelector:#selector(insertInManagedObjectContext:)] && context != nil)
{
id entity = [self performSelector:#selector(insertInManagedObjectContext:) withObject:context];
return entity;
}
else
{
NSEntityDescription *entity = nil;
if (context == nil)
{
entity = [self MR_entityDescription];
}
else
{
entity = [self MR_entityDescriptionInContext:context];
}
if (entity == nil)
{
return nil;
}
return [[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
}
}
#end
The privateContext is a local variable for each operation so I have private contexts for each operation in order to not interrupt the main one. The point is that I create one private context for each thread and I'm just trying to create a new NSManagedObject instance using this context and Xcode says that I'm violating the multithreading core data rules. Does anyone have any clue on what's happening?
We have the same issue when developing our own app.
When you try to perform a write operation in a thread different to the context one, it crash sometimes.
Our solution was to make a private manager on the AppDelegate.m file. Just add this code:
- (NSManagedObjectContext *)getPrivateManagedObjectContext
{
if (self.managedObjectContext != nil) {
return self.managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self getPersistentStoreCoordinator];
if (coordinator != nil) {
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[self.managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return self.managedObjectContext;
}
Then when you need to perform any operation, you should use this method that ensures the block is running on the same thread of the context:
[self.managedObjectContext performBlock:^{...}];
[self.managedObjectContext performBlockAndWait:^{...}];

NSFetchedResultsControllerDelegate methods not called when UITableView is a subview of UIView (data initially loads)

I have a UIView that contains a UITableView. These are managed by a UIViewController that inherits the delegate methods UITableViewDelegate and NSFetchedResultsControllerDelegate. I am able to populate the table just fine using the NSFetchedResultsController, however the delegate methods (specifically controllerWillChangeContent) are not called when changes are made to managed objects in the fetchObjects.
I have checked independently that changes are made to the objects, and those changes I have reflected in the cells, however you must manually reload the cells (scrolling up) to see the changes occur. The behavior I am looking for is that when the changes are made to the object (via save), that the NSFetchedResultsControllerDelegate methods fire so I can make the updates to the table view.
Just to be clear, the data is populated from the database when the view loads, so I know the code pulls that just fine.
Header interface
#interface HSAwardsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate>
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#end
init method - Setting up managedObjectContext (uses Magical Record)
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
HSInternalDB *dbInstance = [HSInternalDB getInternalDB];
self.persistentStoreCoordinator = [dbInstance getPersistentStoreCoordinator];
self.managedObjectContext = [NSManagedObjectContext MR_contextWithStoreCoordinator:self.persistentStoreCoordinator];
self.tableView.delegate = self;
self.tableView.dataSource = self;
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
return self;
}
Setting up the NSFetchedResultsController and assigning the delegate
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Award"];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"gameTypeIdentifier" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
NSError *error = nil;
[theFetchedResultsController performFetch:&error];
theFetchedResultsController.delegate = self;
self.fetchedResultsController = theFetchedResultsController;
// Listen for this notification so that the managedObjectContext runs on the main thread
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];
return _fetchedResultsController;
}
- (void)contextChanged:(NSNotification*)notification
{
NSManagedObjectContext *context = [notification object];
if ([context isEqual:self.managedObjectContext]) {
return;
}
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
As far as I can see, all the connections are are made in code or in the storyboard. I know a change is recorded in my database because I am listening for the NSManagedObjectContextDidSaveNotification.
This has me stumped, so I appreciate any suggestions or bread crumbs. I'm happy to answer any questions or post more code if needed!
contextChanged: should be called on MainThread since it involve UI update.

Adding Core Data to existing iPhone project

I'd like to add core data to an existing iPhone project, but I still get a lot of compile errors:
- NSManagedObjectContext undeclared
- Expected specifier-qualifier-list before 'NSManagedObjectModel'
- ...
I already added the Core Data Framework to the target (right click on my project under "Targets", "Add" - "Existing Frameworks", "CoreData.framework").
My header-file:
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
[...]
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
What am I missing? Starting a new project is not an option...
Thanks a lot!
edit
sorry, I do have those implementations... but it seems like the Library is missing... the implementation methods are full with compile error like "managedObjectContext undeclared", "NSPersistentStoreCoordinator undeclared", but also with "Expected ')' before NSManagedObjectContext" (although it seems like the parenthesis are correct)...
#pragma mark -
#pragma mark Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store
coordinator for the application.
*/
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created by merging all of the models found in
application bundle.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
return managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"Core_Data.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:nil error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should
not use this function in a shipping application, although it may be useful during
development. If it is not possible to recover from the error, display an alert panel that
instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object
model
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
All the CoreData header files are imported in App_Prefix.pch, so the CoreData classes will be available throughout your Project, so you don't have to manually import the header in the files you need them.
So open up Xcode and look for some file like App_Prefix.pch, by default it's in the Other Sources group. After the UIKit import statement, add the following line:
#import <CoreData/CoreData.h>
And you should be ready to go.
Xcode 4
For projects created in Xcode 4, the prefix file can be found in the Supporting Files group in the Project navigator. It's called 'projectname-Prefix.pch' by default.
Xcode 6+
Starting with Xcode 6, the precompiled header file is no longer included by default. This is because of the introduction of Modules, which take away the need to use precompiled headers. While it is still possible to manually add a PCH file to globally include the CoreData headers, consider specifying the CoreData dependency using #import CoreData;* in every file that uses CoreData. This makes dependencies explicit and more importantly will avoid this question's problem in the future.
* Modules need to be enabled for this to work.
Just to expound on all the steps you actually need to perform to add Core Data to a project that previously did not have it:
Step 1: Add the Framework
Click on your app target (on the left pane its the top icon with the name of your app) then go to the 'Build Phases' tab then on 'Link Binary With Libraries', click the little '+' at the bottom then find 'CoreData.framework' and add it to your project
Then either import coredata on all the objects you need it (the non-sexy way) using:
Swift
import CoreData
Objective C
#import <CoreData/CoreData.h>
or add the import below the common imports in your .pch file (much more sexy) like this:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#endif
Step 2: Add the Data Model
To add the .xcdatamodel file right click/control-click on your files in the right pane (like in a Resources folder for safe keeping) and select to Add a New File, Click the Core Data tab when selecting your file type then Click 'Data Model', give it a name and click Next and Finish and it will add it to your project. When you click on this Model object you will see the interface to add the Entities to your project with any relationships you want.
Step 3: Update App Delegate
In Swift on AppDelegate.swift
//replace the previous version of applicationWillTerminate with this
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
func saveContext () {
var error: NSError? = nil
let managedObjectContext = self.managedObjectContext
if managedObjectContext != nil {
if managedObjectContext.hasChanges && !managedObjectContext.save(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
}
// #pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
var managedObjectContext: NSManagedObjectContext {
if !_managedObjectContext {
let coordinator = self.persistentStoreCoordinator
if coordinator != nil {
_managedObjectContext = NSManagedObjectContext()
_managedObjectContext!.persistentStoreCoordinator = coordinator
}
}
return _managedObjectContext!
}
var _managedObjectContext: NSManagedObjectContext? = nil
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
var managedObjectModel: NSManagedObjectModel {
if !_managedObjectModel {
let modelURL = NSBundle.mainBundle().URLForResource("iOSSwiftOpenGLCamera", withExtension: "momd")
_managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
}
return _managedObjectModel!
}
var _managedObjectModel: NSManagedObjectModel? = nil
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
var persistentStoreCoordinator: NSPersistentStoreCoordinator {
if !_persistentStoreCoordinator {
let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("iOSSwiftOpenGLCamera.sqlite")
var error: NSError? = nil
_persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
NSFileManager.defaultManager().removeItemAtURL(storeURL, error: nil)
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
return _persistentStoreCoordinator!
}
var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil
// #pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
var applicationDocumentsDirectory: NSURL {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.endIndex-1] as NSURL
}
In Objective C make sure to add these objects to AppDelegate.h
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory; // nice to have to reference files for core data
Synthesize the previous objects in AppDelegate.m like this:
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
Then add these methods to AppDelegate.m (make sure to put the name of the model that you added in the spots shown):
- (void)saveContext{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (NSManagedObjectContext *)managedObjectContext{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"NAMEOFYOURMODELHERE" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"NAMEOFYOURMODELHERE.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
Step 4: Get the Data Objects to the ViewControllers Where You Need the Data
Option 1. Use the App Delegate's ManagedObjectContext from VC (Preferred and Easier)
As suggeted by #brass-kazoo - Retrieve a reference to AppDelegate and its managedObjectContext via:
Swift
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.managedObjectContext
Objective C
[[[UIApplication sharedApplication] delegate] managedObjectContext];
in your ViewController
Option 2. Create ManagedObjectContext in your VC and have it match AppDelegate's from the AppDelegate (Original)
Only showing old version for Objective C since much easier to use the preferred method
in the ViewController.h
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
In the ViewController.m
#synthesize managedObjectContext = _managedObjectContext;
In the AppDelegate, or class where the ViewController is created set the managedObjectContext to be the same as the AppDelegate one
ViewController.managedObjectContext = self.managedObjectContext;
If you want the viewcontroller using Core Data to be a FetchedResultsController then you'll need to make sure this stuff is in your ViewController.h
#interface ViewController : UIViewController <NSFetchedResultsControllerDelegate> {
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
And this is in ViewController.m
#synthesize fetchedResultsController, managedObjectContext;
After all of that you can now use this managedObjectContext to run all the usual fetchRequests needed for CoreData goodness! Enjoy
For Swift 3: INCLUDES SAVING AND RETRIEVING DATA
Step 1: Add Framework
Step 2: Add Data model
File > New > File > Core Data > Data Model
Name the file as SampleData the resultant file would be SampleData.xcdatamocelId
Step 3: Add the below functions to your App Delegate and add "import CoreData" to the top
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
// SEE BELOW LINE OF CODE WHERE THE 'name' IS SET AS THE FILE NAME (SampleData) FOR THE CONTAINER
let container = NSPersistentContainer(name: "SampleData")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
STEP 4: Adding Entity and Attribute to the Model
a) Add Entity
b) Add Attribute
STEP 5: Saving Data
func saveItem(itemToSave: String){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
//**Note:** Here we are providing the entityName **`Entity`** that we have added in the model
let entity = NSEntityDescription.entity(forEntityName: "Entity", in: context)
let myItem = NSManagedObject(entity: entity!, insertInto: context)
myItem.setValue(itemToSave, forKey: "item")
do {
try context.save()
}
catch{
print("There was an error in saving data")
}
}
STEP 5: Retrieving Data
override func viewWillAppear(_ animated: Bool) {
// Obtaining data from model
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
do {
let results = try context.fetch(fetchRequest)
let obtainedResults = results as! [NSManagedObject]
let firstResult = obtainedResults[0]
let myValue = firstResult.value(forKey: "item")
print("myValue: \(myValue)")
} catch {
print("Error")
}
}
Try creating Core Data backed Cocoa application and look at AppDelegate. You'll see core data stack implementation methods there as well as managed object model file for defining your entities and other core-data releated stuff.
You've shown us only header (i.e. declaration), but not implementation (i.e. definition) of the Core Data stack.
If you run into this same issue in xcode 4, as I did.
It is different: I had to select the project, then in targets expand "Link Binary With Libraries" which shows the current libraries.
From there click the + (plus sign) to select any additional libraries you need.
I placed it in the top of the project and had to move it (drag and drop) to the Frameworks Group, but that was it.
As Eimantas stated your missing the implementiation of the Core Stack, like
- (NSManagedObjectContext *) managedObjectContext;
- (NSManagedObjectModel *)managedObjectMode;
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
On solution would be to create a new core data driver project and copy / paste the implementation to your project.
For Swift 3:
File->new file->CoreData->Model to create a model.
Refer to this link for more information on how to implement it.
//in Swift 2.2 , you may do the following without changing the AppDelegate file.
Project->targets-->linked frameworks and libraries
Now add a new framework (click on +) 'CoreData'
File->new file->CoreData->DataModel
name it as say A.xcdatamodelid
In A.xcdatamodelid create new enitity (click on entity+)
name it as say Bc and set its class as 'Bc' in inspector window on right.
Now Add attributes to the entity (click on attributes +) , add one attribute for eg : name and its type as String.
Now editor->create NSManagedObject Subclass -->click next on the pop up window-->again next-->then click create.
Two new files will be created 1. a new class named Bc.swift and an extension named Bc+coredataproperties.swift.
File->new file->ios->cocoa Touch class-->set its subclass as NSObject->name it as DataController.swift
Inside the file include
///
import UIKit
import CoreData
class DataController: NSObject {
var managedObjectContext: NSManagedObjectContext
override init() {
// This resource is the same name as your xcdatamodeld contained in your project.
guard let modelURL = NSBundle.mainBundle().URLForResource("A", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
self.managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
self.managedObjectContext.persistentStoreCoordinator = psc
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let docURL = urls[urls.endIndex-1]
/* The directory the application uses to store the Core Data store file.
This code uses a file named "A.sqlite" in the application's documents directory.
*/
let storeURL = docURL.URLByAppendingPathComponent("A.sqlite")
do {
try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
}
}
//////
Now inside the viewcontroller file you can access your db using two methods.
Important : include the statement in your viewController
"import CoreData"
a. call seed() -->to insert value into db/entity
b. call fetch()--> to fetch value from db/entity
///////seed()-->def
func seedPerson() {
// create an instance of our managedObjectContext
let moc = DataController().managedObjectContext
// we set up our entity by selecting the entity and context that we're targeting
let entity = NSEntityDescription.insertNewObjectForEntityForName("Bc", inManagedObjectContext: moc) as! Bc
// add our data
entity.setValue("Meera", forKey: "name")
// we save our entity
do {
try moc.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
//fetch() def
func fetch() {
let moc = DataController().managedObjectContext
let personFetch = NSFetchRequest(entityName: "Bc")
do {
let fetchedPerson = try moc.executeFetchRequest(personFetch) as! [Bc]
print(fetchedPerson.first!.name!)
} catch {
fatalError("Failed to fetch person: \(error)")
}
}
view.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface ViewController :
UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *coreDataList;
- (IBAction)addBtnClick:(id)sender;
#property (strong, nonatomic) NSMutableArray *dataList;
#end
detail.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface DetailViewController : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameTxt;
#property (weak, nonatomic) IBOutlet UITextField *mobileTxt;
#property (weak, nonatomic) IBOutlet UITextField *emailIdTxt;
- (IBAction)saveBtnClick:(id)sender;
#property (strong,nonatomic) NSManagedObject *userData;
#end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
if (self.userData) {
[self.nameTxt setText:[self.userData valueForKey:#"name"]];
[self.mobileTxt setText:[self.userData
valueForKey:#"mobileNumber"]];
[self.emailIdTxt setText:[self.userData valueForKey:#"email"]];
[self.imgView setImage:[UIImage imageWithData:[self.userData
valueForKey:#"imageView"]]]; }
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
/*
#pragma mark - Navigation
- (IBAction)browseBtn:(id)sender
{
UIImagePickerController *imgpic =[[UIImagePickerController
alloc]init];
imgpic .delegate =self;
imgpic .sourceType =UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imgpic animated:YES completion:nil];
}
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
UIImage *choose = info[UIImagePickerControllerOriginalImage];
self.imgView.image=choose;
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)saveBtnClick:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.userData) {
// Update existing data
[self.userData setValue:self.nameTxt.text forKey:#"name"];
[self.userData setValue:self.mobileTxt.text
forKey:#"mobileNumber"];
[self.userData setValue:self.emailIdTxt.text forKey:#"email"];
UIImage *sampleimage = _imgView.image;
NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 1.0);
[self.userData setValue:dataImage forKey:#"imageView"];
} else {
// Create a new data
NSManagedObject *newDevice = [NSEntityDescription
insertNewObjectForEntityForName:#"Details"
inManagedObjectContext:context];
[newDevice setValue:self.nameTxt.text forKey:#"name"];
[newDevice setValue:self.mobileTxt.text forKey:#"mobileNumber"];
[newDevice setValue:self.emailIdTxt.text forKey:#"email"];
UIImage *sampleimage = _imgView.image;
NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 1.0);
[newDevice setValue:dataImage forKey:#"imageView"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface DetailViewController :
UIViewController<UITextFieldDelegate,UINavigationControllerDelegate,
UIIma
gePickerControllerDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameTxt;
#property (weak, nonatomic) IBOutlet UITextField *mobileTxt;
#property (weak, nonatomic) IBOutlet UITextField *emailIdTxt;
#property (weak, nonatomic) IBOutlet UIImageView *imgView;
- (IBAction)browseBtn:(id)sender;
- (IBAction)saveBtnClick:(id)sender;
#property (strong,nonatomic) NSManagedObject *userData;
#end
let alert = UIAlertController(title:"Error", message: "No Internet Connection", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in}))
alert.addAction(UIAlertAction(title: "Try Again", style: .default, handler: { (action) in
self.networkCall(text: self.daySelected)
}))
self.present(alert, animated: false, completion: nil)
+(void) insetPlusUpdate:(NSDictionary *)dataa {
NSManagedObjectContext * context;
if (![[NSThread currentThread] isMainThread]) {
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[APP_DELEGATE persistentStoreCoordinator]];
} else {
context = [APP_DELEGATE managedObjectContext];
}
NSFetchRequest * request = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"EntityName" inManagedObjectContext:context];
[request setEntity:entity];
NSPredicate * check = [NSPredicate predicateWithFormat:#"attribute == %#", Dict[#"key"]];
[request setPredicate:check];
NSError * error = nil;
if ([context countForFetchRequest:request error:&error] == 0) {
Entity.attribute = #"";
} else {
NSArray * array = [context executeFetchRequest:request error:&error];
EntityName * entity = [array firstObject];
Entity.attribute = #"";
}
}
+(NSString *)fetch:(NSString *)feed_id{
NSManagedObjectContext * context;
if(![[NSThread currentThread] isMainThread]){
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[APP_DELEGATE persistentStoreCoordinator]];
} else {
context = [APP_DELEGATE managedObjectContext];
}
NSFetchRequest * request = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"ENTITYNAME" inManagedObjectContext:context];
[request setEntity:entity];
NSPredicate * check = [NSPredicate predicateWithFormat:#"attribute == %#", Dict[#"key"]];
[request setPredicate:check];
NSError * error = nil;
if ([context countForFetchRequest:request error:&error] > 0) {
NSArray * array = [context executeFetchRequest:request error:&error];
ENTITYNAME * fetchData = [array firstObject];
NSString * string = fetchData.attribte[#"key"];
return string;
}
return nil;
}
+(BOOL)delete{
NSManagedObjectContext * context;
if (![[NSThread currentThread] isMainThread]) {
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[APP_DELEGATE persistentStoreCoordinator]];
} else {
context = [APP_DELEGATE managedObjectContext];
}
NSFetchRequest * request = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"ENTITYNAME" inManagedObjectContext:context];
[request setEntity:entity];
NSError *error = nil;
NSBatchDeleteRequest *deleteRequest = [[NSBatchDeleteRequest alloc] initWithFetchRequest: request];
#try{
[context executeRequest:deleteRequest error:&error];
if([context save:&error]){
NSLog(#"Deleted");
return [context save:&error];
}
else{
return [context save:&error];
}
}
#catch(NSException *exception){
NSLog(#"failed %#",exception);
return [context save:&error];
}
}
sample coding view1
#import "ViewController.h"
#import "DetailViewController.h"
#interface ViewController ()
{
NSInteger indexPathvalue;
}
#end
#implementation ViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(#"call this one2");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSManagedObjectContext *managedObjectContext = [self
managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]
initWithEntityName:#"Details"];
self.dataList = [[managedObjectContext executeFetchRequest:fetchRequest
error:nil] mutableCopy];
[_coreDataList reloadData];
NSLog(#"call this one");
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
return self.dataList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell
alloc]initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
NSManagedObject *user = [self.dataList objectAtIndex:indexPath.row];
cell.textLabel.text = [user valueForKey:#"name"];
cell.detailTextLabel.text = [user valueForKey:#"mobileNumber"];
cell.imageView.image = [UIImage imageWithData:[user
valueForKey:#"imageView"]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
indexPathvalue = indexPath.row;
[self performSegueWithIdentifier:#"detailView" sender:self];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:
(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:
(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:
(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[context deleteObject:[self.dataList objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
[self.dataList removeObjectAtIndex:indexPath.row];
[_coreDataList reloadData];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)addBtnClick:(id)sender {
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"detailView"])
{
NSManagedObject *obj = [self.dataList objectAtIndex:indexPathvalue];
DetailViewController *detail = segue.destinationViewController;
detail.userData = obj;
}
}
#end
sample detail view
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
if (self.userData) {
[self.nameTxt setText:[self.userData valueForKey:#"name"]];
[self.mobileTxt setText:[self.userData valueForKey:#"mobileNumber"]];
[self.emailIdTxt setText:[self.userData valueForKey:#"email"]];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
/*
savebutton
- (IBAction)saveBtnClick:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.userData) {
// Update existing data
[self.userData setValue:self.nameTxt.text forKey:#"name"];
[self.userData setValue:self.mobileTxt.text forKey:#"mobileNumber"];
[self.userData setValue:self.emailIdTxt.text forKey:#"email"];
UIImage *sampleimage = [UIImage imageNamed:#"icon.png"];
NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 1.0);
[self.userData setValue:dataImage forKey:#"imageView"];
} else {
// Create a new data
NSManagedObject *newDevice = [NSEntityDescription
insertNewObjectForEntityForName:#"Details"
inManagedObjectContext:context];
[newDevice setValue:self.nameTxt.text forKey:#"name"];
[newDevice setValue:self.mobileTxt.text forKey:#"mobileNumber"];
[newDevice setValue:self.emailIdTxt.text forKey:#"email"];
UIImage *sampleimage = [UIImage imageNamed:#"icon.png"];
NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 1.0);
[newDevice setValue:dataImage forKey:#"imageView"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end

Resources