This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Make UIAlertView blocking
Been beating my head against the wall for hours on this one.
Here's what I've got: OrderDetailsViewController is set as an UIAlertViewDelegate
I've got a procedure that receives information back from a search form. It checks to see if the item is already on the order and if not continues adding the item(s). If it sees a duplicate, it pops up a UIAlertView asking what the user wants to do: there are 3 options, "Combine" - add the new qty to the old item, "Add" the duplicate as a separate line item, or "Cancel" throw the new item away. I need it to wait for an answer from the UIAlertView so that I can continue adding the dupe or throwing away the dupe -- the "Combine" is handled in the delegate, but I still need an answer for the main procedure.
Here's what I have so far:
- (void)returnItemAndQty:(ProductsSearchController *)productsSearchController
withItemsToAdd:(NSMutableArray *)itemsToAdd
withQty:(NSDictionary *)qtyToAdd andClose:(BOOL)close
{
if ([itemsToAdd count] == 0) {
return;
}
Items *items;
for (int index = 0; index < [itemsToAdd count]; index++) {
items = [itemsToAdd objectAtIndex:index];
qtyAddedToOrder = [NSDecimalNumber decimalNumberWithString:[qtyToAdd objectForKey:items.ItemCode]];
NSLog(#"Item Code: %#", items.ItemCode);
NSLog(#"Qty: %#", [qtyToAdd objectForKey:items.ItemCode]);
NSError *error;
//For handling duplicate items. . .
duplicateItemDisposition = -1; //Reset the dispostion for normal operation
if([self isItemOnOrder:items.ItemCode])
{
int i = [self itemIsAlreadyOnOrder:itemAlreadyOnOrder withQty:qtyAddedToOrder];
if (i == COMBINE || i == CANCEL){ //either Cancel or Combine was pressed.
items.Checked = NO;
if (![items.managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
continue;
}
}
//Add the new item or duplicate if that's what you want
OrdersDetails *newOrderDetail = [NSEntityDescription insertNewObjectForEntityForName:#"OrdersDetails"
inManagedObjectContext:self.managedObjectContext];
.//more code snipped, that handles the "ADD" or non-dupe
.
.
Here's where it tests for a duplicate. . .
- (BOOL)isItemOnOrder:(NSString *)itemCode
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"OrdersDetails"
inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]initWithKey:#"Desc1" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sort, nil];
[request setSortDescriptors:sortDescriptors];
[sort release];
[sortDescriptors release];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(ItemCode=%# AND OrderID=%#)", itemCode, orders.OrderID];
[request setPredicate:pred];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:& error] mutableCopy];
[request release];
if (mutableFetchResults == nil) {
itemAlreadyOnOrder = nil;
return NO;
}else if ([mutableFetchResults count] > 0){
itemAlreadyOnOrder = [mutableFetchResults objectAtIndex:0];
return YES;
}else{
itemAlreadyOnOrder = nil;
return NO;
}
}
Here's where it sees that a dupe exists and the UIAlertview delegate with it. . .
- (int) itemIsAlreadyOnOrder:(OrdersDetails *)existingOrderDetail withQty:(NSDecimalNumber *)qty
{
if (existingOrderDetail == nil) {
return -1;
}
UIAlertView *duplicateAlert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:#"Duplicate Item %# found.",existingOrderDetail.ItemCode] message:#"Tap Combine to combine the items, Tap Add to add the duplicate item or Tap Cancel to discard the duplicate" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Combine", #"Add", nil];
[duplicateAlert show];
return duplicateItemDisposition;
[duplicateAlert release];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Cancel = 0, Combine = 1, Add = 2
if (buttonIndex == CANCEL){
duplicateItemDisposition = CANCEL;
}else if (buttonIndex == COMBINE){
duplicateItemDisposition = COMBINE;
NSDecimalNumber *existingQty = [[NSDecimalNumber alloc] initWithDecimal:[itemAlreadyOnOrder.Qty decimalValue]];
NSDecimalNumber *existingPrice = itemAlreadyOnOrder.Price;
NSDecimalNumber *newQty = [existingQty decimalNumberByAdding:qtyAddedToOrder];
itemAlreadyOnOrder.ExtPrice = [newQty decimalNumberByMultiplyingBy:existingPrice];
[existingQty release];
NSError *error;
if (![itemAlreadyOnOrder.managedObjectContext save:&error]){
NSLog(#"Error saving. %#, %#", error, [error userInfo]);
[self handleFreeGoods:itemAlreadyOnOrder];
}else if (buttonIndex == ADD){
duplicateItemDisposition = ADD;
}
}
Now I read something on here about using an NSCondition in a background thread, but I have no idea what that means. I looked up NSCondition, and it was less than enlightening.
Any ideas on how to pause the execution?
The UIAlertView can't block, as it gets displayed at the end of the runloop. Instead of having the method itemIsAlreadyOnOrder: return a value indicating what should be done with the duplicate entry, the delegate method from the UIAlertView needs to notify your controller that the item in question has been resolved. Track the object in question somewhere (_objectToVerify or something like that), and in the delegate method from the UIAlertView call a method based on the users choice, which will act on that _objectToVerify.
I don't know how much this might change your current design, but the Cocoa design pattern would have the method that puts up the alert not return anything, so something like if (duplicate) showAlertView in pseudocode. Then in the alert view's delegate, call a method that actually handles the processing of the duplicate based on user input.
Related
I've just read some tutorials and decide to add Core Data storage to my project. Then I implement "create" and "read" methods. It works OK.
But then I encountered a problem with "update" method.
- (void)updateForecastPlace:(NSString *)placeString
{
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:ENTITY_NAME inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
WFForecast *forecastToUpdate;
for (WFForecast *forecast in fetchedObjects)
{
if ([[forecastToUpdate timestamp] compare:[forecast timestamp]] == NSOrderedAscending)
{
forecastToUpdate = forecast;
}
}
[forecastToUpdate setPlace:placeString];
error = nil;
if ([context save:&error])
{
NSLog(#"Forecast information was updated!");
}
else
{
NSLog(#"The forecast information was not updated: %#", [error userInfo]);
}
}
I'm fetching objects from context. (It's OK)
Then choose one to update.
Setup new value to its property( [forecastToUpdate setPlace:placeString];)
Then save the context. ( [context save:&error] )
It seems like it works (it's rise no errors and send success massage to console log). But when I read this object it appears to be non-updated.
I read a lot of stuff on this problem but didn't figure out how to fix it.
Any suggestions, please?
UPDATE: I check the value of my updated object property place
[forecastToUpdate setPlace:placeString];
NSLog(#"---arg value %#", placeString);
NSLog(#"---updated value %#", [forecastToUpdate place]);
and got the output like:
---arg value Sydney, Australia
---updated value (null)
Any idea what caused such mistake?
Unfortunately the problem was in my inattentiveness :(
I forgot to assign fetched object with my objectToUpdate pointer before compare values and do other stuff.
WFForecast *lastestForecast = fetchedObjects[0]; // <- missed this row
for (WFForecast *forecast in fetchedObjects)
{
NSLog(#"%#", [forecast place]);
if ([[lastestForecast timestamp] compare:[forecast timestamp]] == NSOrderedAscending)
{
lastestForecast = forecast;
}
}
so I'm doing application form using CoreData
First I'm creating "Shop" with unique name and some properties.
In application you can edit that "Shop", and I'm trying to make validation by "shopName" to avoid a creation another "Shop" with same name.
I'm using this:
-(BOOL)uniqueEntityExistsWithEnityName {
BOOL returnValue = NO;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Shop"];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"shopName = [cd] %#", _shopName.text];
NSSortDescriptor *shop = [[NSSortDescriptor alloc] initWithKey:#"shopName" ascending:YES];
[request setSortDescriptors: #[shop]];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *matches = [self.managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"request = %#",predicate);
if (!matches) {
NSLog(#"Error: Couldn't execute fetch request %#", error);
}
else if([matches count] > 1) {
NSString *existShop = [NSString stringWithFormat:#"Could Be Only One %# Shop", _shopName.text];
UIAlertView *exist = [[UIAlertView alloc]initWithTitle:#"Shop Exists in Your Records"
message:existShop
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[exist show];
NSLog(#"Error: Have more than %lu records",
(unsigned long)[matches count]);
returnValue = YES;
}
else {
NSLog(#"%lu object in record", (unsigned long)[matches count]);
[self oldShopDelete];
[self checkShopPhoneNumber];
editShop.shopName = _shopName.text;
editShop.shopPhoneNumber = _shopPhoneNumber.text;
editShop.shopSecondPhoneNumber = _shopSecondPhoneNumber.text;
editShop.shopEmail = _shopEmail.text;
editShop.shopNote = _shopNoteView.text;
[super saveAndDissmiss];
returnValue = YES;
}
return returnValue;
}
With that code you still have opportunity to save one more edited "Shop" with same name.
But the thing is - I can not make [matches count] = 1 after this I'll no chance to edit that Shop
Maybe there are another way to do such validation?
Check for a name clash only when the Name is actually being set for the first time or edited.
You can also pass the current shop into the predicate to ensure AND SELF != %# so there will be no match with an existing shop being edited but with an unchanged name.
I'm missing something in my logic when trying to sync web service data with local store and I need your help. This is what I've got:
I have one NSArray of NSDictionaries describing each event object (downloaded from web), which I sort by event id. Then I fetch local store using IN predicate and also sort it by event id. Then I try to iterate and match the ids and if they match, i update record and if they don't match i create new NSManagedObject. It works fine if the newly downloaded event object has a greater eventID than last eventID in local store, but if the eventID from web service is smaller than the one in local store then it INSERTS ALL OBJECTS, no matter if they exist or not and that exactly is my problem.
So in other words, if a new record is at the beginning of sorted array it will add every object, but if it is at the end of sorted array it will update all except the new one. I need it to create the new one and update old ones.
Here's some code:
The function with the logic where I believe I'm missing something:
- (void)findOrCreateObject:(NSArray*)eventArray
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
//get sorted stored records
NSArray *fetchedRecords = [self.fetchedResultsController fetchedObjects];
//sort dictionaries
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
NSArray *downloadedRecords = [self.events sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
NSLog(#"DOWNLOADED EVENTS = %#", downloadedRecords);
NSLog(#"FETCHED EVENTS = %#", fetchedRecords);
//if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
if (fetchedRecords.count != 0) {
//stores has records already
NSLog(#"FIND OR CREATE PROCESS");
if ([downloadedRecords count] > 0) {
NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];
NSUInteger currentIndex = 0;
for (NSDictionary* event in downloadedRecords) {
Event* eventObject = nil;
if ([storedRecords count] > currentIndex) {
eventObject = [storedRecords objectAtIndex:currentIndex];
}
NSLog(#"STRING VALUE OF KEY = %#", [[eventObject valueForKey:#"eventID"]stringValue]);
if ([[event valueForKey:#"id"] isEqualToString:[[eventObject valueForKey:#"eventID"] stringValue]]) {
//Update Record
NSLog(#"Updating Record!!!");
[self updateManagedObject:eventObject withRecord:event inContext:context];
}
else
{
//New Record
NSLog(#"Inserting Record!!!");
eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:#"id"]];
eventObject.title = [event valueForKey:#"title"];
eventObject.venue = [event valueForKey:#"venue"];
}
currentIndex++;
}
}
}
else
{
//import initial data
NSLog(#"IMPORTING INITIAL DATA");
for (NSDictionary* event in downloadedRecords) {
Event *eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:#"id"]];
eventObject.title = [event valueForKey:#"title"];
eventObject.venue = [event valueForKey:#"venue"];
}
}
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
The FETCHEVENTS method:
-(NSArray*)fetchEvents:(NSArray*)eIDs withContext:(NSManagedObjectContext*)context
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eventID IN %#)", eIDs];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:#[ [[NSSortDescriptor alloc] initWithKey: #"eventID" ascending:YES] ]];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"No rows returned");
}
return fetchedObjects;
}
The Update Object method:
- (void)updateManagedObject:(NSManagedObject*)object withRecord:(NSDictionary*)record inContext:(NSManagedObjectContext*)context
{
[object setValue:[self makeNumberFromString:[record valueForKey:#"id"]] forKey:#"eventID"];
[object setValue:[record valueForKey:#"title"] forKey:#"title"];
[object setValue:[record valueForKey:#"venue"] forKey:#"venue"];
}
I'm calling findOrCreate method once I download the web service data and parse it.
Let me know if you have any other questions.
Try this,
- (void)findOrCreateObject:(NSArray*)eventArray {
//if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
if (fetchedRecords.count != 0) {
//stores has records already
NSLog(#"FIND OR CREATE PROCESS");
if ([downloadedRecords count] > 0) {
NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];
for (NSDictionary* event in downloadedRecords) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"eventID = %#",[event valueForKey:#"id"]];
NSArray *matchedArray = [storedRecords filteredArrayUsing
Predicate:predicate];
Event* eventObject = nil;
if ([matchedArray count] > 0) {
//Update Record
NSLog(#"Updating Record!!!");
eventObject = [matchedArray objectAtIndex:0];
[self updateManagedObject:eventObject withRecord:event inContext:context];
}
else
{
//New Record
NSLog(#"Inserting Record!!!");
eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
eventObject.eventID = [self makeNumberFromString:[event valueForKey:#"id"]];
eventObject.title = [event valueForKey:#"title"];
eventObject.venue = [event valueForKey:#"venue"];
}
}
}
} else {
.....
}
}
I think, every time you insert a new event object, you should update storedObjects such that it should now contain the inserted object.
Or more simply, you should put the initialisation line of storedObjects inside your for loop. (This would make sure that as you enumerate from the beginning of downloadedObjects every eventObject will have the same index on it as on storedObjects. But, with regards to your code this will only be true if all elements of storedObjects will always be found in downloadedObjects which, I assume is the case.)
One thing though, isn't fetchedRecords supposed to be the same as storedObjects, if they are you should just reassign storedObjects as [self.fetchedResultsController fetchedObjects], as it would reflect the changes in your context without executing another fetch request which would solve the inefficiency of the suggestion above.
After trying to figure out in my previous question what is the exact problem:
fetchedObjects (NSArray) count return 0 when it's full of objects
I'm pretty sure I need my core data to be async from multiple classes and threads.
I tried multiple calls to my core data in a row, one by one and I had no problem.
But obviously I need it to be read/write from multiple classes and threads.
I trued using #synchronized and still nothing, I've an 0 records in fetchedObjects array from core data but there's are data in there.
What is the correct approach to do it?
EDIT 1:
The code above works only once if I'm trying to schedule it using NSTimer:
TrapService.mm:
self.managedObjectContext = appDelegate.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"fetchedObjects.count: %d", fetchedObjects.count);
EDIT 2:
Another example of codes i'm using with core data, execute once, then all of the operations regarding core data doing nothing or giving me back array with 0 records.
TrapService.mm:
- (void)initializeQuadTree
{
self.qTree = [[QuadTree alloc] init];
self.qTree = [dbat addCoordinatesToQuadTree:self.qTree];
}
- (Traps*)getCloseTrapFromTree:(CLLocation*)location
{
return [dbat getCloseTrapFromTree:self.qTree andLocation:location];
}
DataBaseAllTraps.m:
- (QuadTree*)addCoordinatesToQuadTree:(QuadTree*)quadTree
{
if (quadTree == nil) {
quadTree = [[QuadTree alloc] init];
}
BOOL success = YES;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil || fetchedObjects.count == 0)
{
NSLog(#"addCoordinatesToQuadTree - localizedDescription: %#, userInfo: %#", error.localizedDescription, error.userInfo);
success = NO;
}
NSLog(#"addCoordinatesToQuadTree - fetchedObjects.count: %d", fetchedObjects.count);
if (success)
{
for (CoreDataAllTraps *trap in fetchedObjects)
{
double latitude = trap.lat.doubleValue;
double longitude = trap.lon.doubleValue;
double closePointLat = trap.close_point_lat.doubleValue;
double closePointLon = trap.close_point_lon.doubleValue;
DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];
if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);
[quadTree insertObject:trapAnnotation];
}
}
else
{
for (Traps *trap in kNETROADS_CONTEXT.arrayOfAllTraps)
{
double latitude = trap.lat;
double longitude = trap.lon;
double closePointLat = trap.closePointLat;
double closePointLon = trap.closePointLon;
DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];
if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);
[quadTree insertObject:trapAnnotation];
}
}
NSLog(#"TOTAL NUMBER OF TRAPS (%s): %i", __PRETTY_FUNCTION__, success?fetchedObjects.count:[Netroads sharedInstance].arrayOfAllTraps.count);
return quadTree;
}
- (Traps*)getCloseTrapFromTree:(QuadTree*)quadTree andLocation:(CLLocation*)location
{
NSLog(#"%s", __PRETTY_FUNCTION__);
NSArray *closeTraps = [quadTree neighboursForLocation:location.coordinate limitCount:1];
if (closeTraps.count == 0) { return nil; }
// NSAssert(closeTraps.count > 0, #"closeTraps.count == 0, get close trap from quad tree.");
int trapID = 0;
DummyAnnotation *trapLocation = closeTraps.firstObject;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# == %f AND %# == %f", CLOSE_POINT_LAT, trapLocation.coordinate.latitude, CLOSE_POINT_LON, trapLocation.coordinate.longitude];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchLimit:1];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects != nil && fetchedObjects.count > 0) { // We have close point
CoreDataAllTraps *trap = fetchedObjects.firstObject;
trapID = trap.trapID.intValue;
}
else { // We do not have close point, use normal coordinates (lat, lon)
NSLog(#"%s error: %#\n%#", __PRETTY_FUNCTION__, error.localizedDescription, error.userInfo);
fetchRequest = [[NSFetchRequest alloc] init];
entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
predicate = [NSPredicate predicateWithFormat:#"%# == %f AND %# == %f", LAT, trapLocation.coordinate.latitude, LON, trapLocation.coordinate.longitude];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchLimit:1];
error = nil;
fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects != nil && fetchedObjects.count > 0) {
CoreDataAllTraps *trap = fetchedObjects.firstObject;
trapID = trap.trapID.intValue;
}
else {
NSLog(#"%s error: %#\n%#", __PRETTY_FUNCTION__, error.localizedDescription, error.userInfo);
}
}
if (trapID > 0) {
return [self getTrap_trapID:trapID];
}
else {
return nil;
}
}
EDIT 3:
I'm creating a new MOC and still nothing, same problems:
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator];
I did not analyze your code. (I'm too lazy. :-)) But when I did a search for a single save I found none.
Please remember, what is going on: In a standard set-up you have one SQL-DB as backend. You have different contexts for each thread/queue that (partially) takes out the data of the SQL-DB on a fetch request and (partially) saves it on a save request.
No context pushes its changes (including insertions and deletions) automatically to the DB or to another context. No context pulls changes pushed by another context automatically from the DB or another context. So transmitting data from context to another one has to be done a way "manually".
As long as you do not have deletions you can simply store the data when one context is done using save and listen to the did save notification on the other thread.
Read up on Apples documentation on how to use CoreData in a concurrent fashion.
Basically it is highly important to use separate NSManagedObjectContext per thread and not to pass objects between these threads, but only reference these by their NSManagedObjectID.
Your code example above needs more information on where you sue that code. But what makes me wonder immediately is
self.managedObjectContext = appDelegate.managedObjectContext;
If not run on main thread, this is exactly contrary to what the concurrency guide tells to do. With that line you only create a pointer that points to appDelegate.managedObjectContext. This is not a new object!
There is usually no need to synchronize or add locks and such, if done the right way.
To give a good answer, though your question is too vague and it would need a rather lengthy answer. But maybe after reading Apple's documentation you may be able to partially solve your problem and come back with questions on problems. that can be answered satisfactorily more easily.
I saw many questions about Core Data updates. Actually I am creating a simple application contact list app. It contains add, edit, delete and update functionalities. Here my update code. It works and updates, but it updates all the contact list. I need to update specific contacts only.
- (IBAction)updatePressed:(id)sender
{
delegate = [[AppDelegate alloc]init];
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
name2 = emailtxt1.text;
email2 = nametext1.text;
mobile2 = numbertxt1.text;
dict = [[NSMutableDictionary alloc] init];
[dict setObject:nametext1.text forKey:#"NAME"];
[dict setObject:emailtxt1.text forKey:#"EMAIL"];
[dict setObject:numbertxt1.text forKey:#"MOBILE"];
[delegate UpdateDiary:dict];
}
- (void)UpdateDiary:(NSMutableDictionary *)dictionary
{
NSLog(#"update book Details Function Entered");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Diary"inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *mutableFetchResult = [[[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy] autorelease];
if (mutableFetchResult == nil) {
NSLog(#"Fetch result error %#, %#", error, [error userInfo]);
}
for (Diary *ob2 in mutableFetchResult)
{
{
ob2.name = [dictionary objectForKey:#"NAME"];
ob2.email=[dictionary objectForKey:#"EMAIL"];
ob2.phone=[dictionary objectForKey:#"MOBILE"];
}
}
if(![self.managedObjectContext save:&error])
{
if([error localizedDescription] != nil)
{
NSLog(#"%#",error);
}
else
{
}
}
}
You need to set a predicate on your fetch request. That's how it knows which object(s) you want, rather than just fetching them all.
You could do something like:
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"email == %#", anEmailAddress];
If you did that, then the result of executing the fetch request would just be objects that matched the email address you set in the predicate.
Note, of course, that if there is more than one object with the same email address, then the fetch request would fetch all of them.
A better design for your app might be, when you go into the edit form, keep around the Core Data object that you're editing, possibly in a property on your view controller. (You'll have it around at that point I reckon, since you'll need to know what to populate the fields with.) That way you don't need to perform a fetch at the time the user is trying to commit the edit — you can just use the object you've kept around.
- (void)UpdateBook:(NSMutableDictionary *)dictionary
{
NSLog(#"update book Details Function Entered");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Book"inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"bookID = %#", [dictionary objectForKey:#"vID"]];
NSArray *mutableFetchResult = [[[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy] autorelease];
if (mutableFetchResult == nil) {
NSLog(#"Fetch result error %#, %#", error, [error userInfo]);
}
for (Book *ob2 in mutableFetchResult)
{
{
ob2.name = [dictionary objectForKey:#"VName1"];
ob2.author=[dictionary objectForKey:#"VAuthor1"];
ob2.discription=[dictionary objectForKey:#"VDiscription1"];
ob2.bookID=[dictionary objectForKey:#"vID"];
}
}
if(![self.managedObjectContext save:&error])
{
if([error localizedDescription] != nil)
{
NSLog(#"%#",error);
}
else
{
}
}
}