Can someone help me. I have a coredata application but I need to save the objects from a fetchedResultsController into an NSDictionary to be used for sending UILocalNotifications.
Should I use an NSMutableSet, or a NSDictionary, or an array. I'm not used to using collections and I can't figure out the best way to do that.
Could you please give me clues on how to do that please ?
Thanks,
Mike
If I'm reading your question correctly, you're asking how you should pack objects into the userInfo dictionary of a UILocalNotification. Really, it's however works best for you; userInfo dictionaries are created by you and only consumed by you.
I'm not sure why you would be using an NSFetchedResultsController - that class is for managing the marshaling of managed objects between UI classes (like UITableView) efficiently, whereas here it sounds like you would be better off just getting an NSArray of results from your managedObjectContext and the corresponding request, like this:
NSError *error = nil;
NSArray *fetchedObjects = [myManagedObjectContext executeFetchRequest: myRequest error: &error];
if (array == nil)
{
// Deal with error...
}
where you have a pre-existing managed object context and request. You don't need to use an NSFetchedResultsController here.
From there, the simplest suggestion would be to build your userInfo dictionary like this:
NSDictionary* myUserInfo = [NSDictionary dictionaryWithObject: fetchedObjects forKey: #"AnythingYouWant"];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
// ... do other setup tasks ...
localNotif.userInfo = myUserInfo;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
Then when it comes time to receive that notification, you can read that dictionary like this:
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif
{
NSArray* myFetchedObjects = [notif.userInfo objectForKey: #"AnythingYouWant"];
for(id object in myFetchedObjects)
{
// ... do other stuff ...
}
}
Now, hopefully that's clarified how the userInfo dictionary works. I don't know the details of your app, so it's hard to say, but I'm suspicious that actually passing fetched objects is NOT what you want to do here, mainly because I'm not sure that you have any guarantee that the receiving delegate method will be working with the same object context as the sending method. I would suggest perhaps putting the entity name and predicate in the dictionary and then refetching the objects at receive time with whatever the current MOC is at that moment.
Good luck!
Related
I have the following core-data structure:
I am trying to add Vocabulary objects to the Group class.
My attempts at doing this with the [Group addObject: VocabularyObject] method have
come to no avail.
AppDelegate *delegate = [[AppDelegate alloc]init];
Group *group = [_arr objectAtIndex:indexPath.row]; //I have an array with 'Group' objects
//create vocabulary item
Vocabulary *vocabularyEntity = [NSEntityDescription insertNewObjectForEntityForName:#"Vocabulary" inManagedObjectContext:[delegate managedObjectContext]];
vocabularyEntity.prompt = #"Here is a cool prompt";
vocabularyEntity.definition = #"Here is an even cooler definition";
[delegate saveContext];
[group addTermsObject:vocabularyEntity];
I am getting this error, I used exception breakpoints and the error comes from the addTermsObject call.
[__NSDictionaryI addTermsObject:]: unrecognized selector sent to instance 0x74c4f70
The object I am trying to add is definitely a Vocabulary object, so i'm not exactly sure what the problem could be.
Any ideas?
Thank you!
The error message states that your
Group *group = [_arr objectAtIndex:indexPath.row];
is not a managed object as you expected, but an NSDictionary. Perhaps you fetched the array using
[fetchRequest setResultType:NSDictionaryResultType];
in the fetch request? In that case all the fetched objects are just dictionaries without
any connection to the managed object context, and you can't use these dictionaries to
establish any relationships.
UPDATE: Another error is here:
AppDelegate *delegate = [[AppDelegate alloc]init];
This allocates a new application delegate instead of using the existing one. This is
probably not what you want and you should replace it with
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
I'm curious to know what the best way is to create a new NSManagedObject in RestKit 0.20? Currently my code looks something like this:
#pragma mark - navigation buttons
- (void)createButtonDidTouch
{
// create new album object
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
NSManagedObjectContext *parentContext = RKObjectManager.sharedManager.managedObjectStore.mainQueueManagedObjectContext;
context.parentContext = parentContext;
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Album" inManagedObjectContext:parentContext];
Album *newAlbum = [[Album alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
// pass object to create view to manipulate
AlbumCreateViewController *createViewController = [[AlbumCreateViewController alloc] initWithData:newAlbum];
createViewController.delegate = self;
createViewController.managedObjectContext = context;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:createViewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:navController animated:YES completion:nil];
}
#pragma mark - create view controller delegate
- (void)createViewControllerDidSave:(NSManagedObject *)data
{
// dismiss the create view controller and POST
// FIXME: add restkit code to save the object
NSLog(#"save the object...");
NSDictionary *userInfo = [KeychainUtility load:#"userInfo"];
NSString *path = [NSString stringWithFormat:#"/albums/add/%#/%#", userInfo[#"userID"], userInfo[#"apiKey"]];
[RKObjectManager.sharedManager postObject:data path:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
operation.targetObject = data;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"create album error: %#", error);
}];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)createViewControllerDidCancel:(NSManagedObject *)data
{
// dismiss the create view controller
NSLog(#"delete the object...");
// FIXME: add restkit code to delete the object
[self dismissViewControllerAnimated:YES completion:nil];
}
I'm also curious to know what my responsibilities are for saving / deleting this object. If I POST to the server via RestKit is the managed object context saved?
What if I decide to cancel this creation process — what's the preferred way to delete this object?
Basically how much is RestKit doing for me, and what should I make sure I'm doing. I haven't found much documentation on this and would like to be clear on it.
When you initialize an RKManagedObjectRequestOperation for a given object, RestKit will obtain a permanent object ID for that object and then create a child managed object context whose parent context is the context the object is inserted into. The operation then executes the HTTP request to completion and obtains a response.
If the response is successful and the mapping of the response is successful (note that the mapping occurs within this private child context), then the private child context is saved. The type of save invoked is determined by the value of the savesToPersistentStore property (see http://restkit.org/api/0.20.0/Classes/RKManagedObjectRequestOperation.html#//api/name/savesToPersistentStore).
When YES, the context is saved recursively all the way back to the persistent store via the NSManagedObjectContext category method saveToPersistentStore (see http://restkit.org/api/0.20.0/Categories/NSManagedObjectContext+RKAdditions.html).
When NO, the context is saved via a vanilla [NSManagedObjectContext save:] message, which 'pushes' the changes back to the parent context. They will remain local to that context until you save them back. Keep in mind that managed object context parent/child hierarchies can be as long as you create within the application.
If the HTTP request failed or there was an error during the mapping process, the private context is not saved and the operation is considered failed. This means that no changes are saved back to the original MOC, leaving your object graph just as it was before the operation was started (except the object being sent, if temporary, now has a permanent object ID but is still unsaved).
The way you do it should works (calling each time the MOC in each of your VC), but is not "recommended".
What Apple suggests, just like any Core Data app, is the "pass the baton" style.
Nested contexts make it more important than ever that you adopt the
“pass the baton” approach of accessing a context (by passing a context
from one view controller to the next) rather than retrieving it
directly from the application delegate.
See here:
http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-CoreData/_index.html
As for your second question, RestKit should manage saving/updating your Core Data stack upon success of your api calls if everything is well mapped/setup.
From blake the RK creator:
if you POST or PUT a Core Data object, RK obtains a permanent object
ID for it and then creates a secondary managed object context, fires
the request, and maps the response (if possible). if the response and
the mapping are successful, it will either save it back to the parent
context or all the way back to the persistent store (i.e. into SQLite)
based on the value of the savesToPersistentStore.
I'm VERY new to Objective C and iOS development (like 5 hours new :-). I've got some code that calls an API to authenticate a user and returns a simple OK or FAIL. I can get the result to write to the console but what I need to do is get that result as part of my IBAction.
Here's the IBAction code:
- (IBAction) authenticateUser
{
[txtEmail resignFirstResponder];
[txtPassword resignFirstResponder];
[self performAuthentication];
if (authResult == #"OK")
What I need is for authResult to be the JSON result (OK or FAIL). Here is the code that gets the result:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", responseString);
[responseData release];
NSMutableDictionary *jsonResult = [responseString JSONValue];
if (jsonResult != nil)
{
NSString *jsonResponse = [jsonResult objectForKey:#"Result"];
NSLog(#"%#", jsonResponse);
}
}
Thank you so much for any help and sorry if I'm missing something obvious!
I'm a little confused as to what's going on here... it looks like your -performAuthentication method must start an asynchronous network request via NSURLConnection, and your connection's delegate's -connectionDidFinishLoading: gets to determine the result of the request. So good so far? But your -authenticateUser method expects authResult to be determined as soon as -performAuthentication returns. If the network request is asynchronous, that's not going to happen. If I'm following you, I think you need to do the following:
Fix up -connectionDidFinishLoading: so that it actually sets authResult based on the Result value in jsonResponse. I'm sure you'd get around to this at some point anyway.
Change -authenticateUser such that it doesn't expect to have an answer immediately. You've got to give the network request a chance to do its thing.
Add another method, possibly called -authenticationDidFinish or something along those lines. Everything currently in -authenticateUser from the 'if (authResult...' to the end goes in this new method.
Call the new method from -connectionDidFinishLoading:.
Fix your string comparison. If you want to compare two strings in Cocoa, you say (for example):
if ([authResult isEqualToString:#"OK") { }
I would like to use an NSArrayController to provide data to an NSTableView. The problem I am facing is that I do not want to pre-load all my data into an array and then use the array controllers setContent: method. My data model is a large existing code base that manages millions of records. It contains methods to efficiently return a set of data rows.
Following an example I found on limiting the number of objects in an NSArrayController, I tried subclassing NSArrayController and overriding the arrangedObjects: method to return an array proxy class I wrote. The array proxy class provided count: and objectAtIndex: methods. The object returned by objectAtIndex: is an NSDictionary. When I tried returning my array proxy from the arrangedObjects: method both count: and objectAtIndex: get called, but I also get an unrecognized selector error on my array proxy class for _valueForKeyPath:ofObjectAtIndex:. This looked like a private method, so I did not continue down this path.
I also thought of returning a smaller array of data from arrangedObjects:, but could not figure out how I would determine which rows the NSTableView was trying to display.
Is a datasource the "correct" way to interface with my existing data model or is there some way to make an NSArrayController work?
NSArrayController already works, with proxies and indexes and lazy-loading and the whole shabang. Have you tried just using it as-is? If afterwards you feel the need to micro-manage the data-loading, use NSFetchRequest. Subclass NSArrayController and add an initializer along these lines:
+ (id)arrayControllerWithEntityName: (NSString *)entityName error:(NSError **)error
{
id newInstance = [[[self alloc] initWithContent:nil] autorelease];
[newInstance setManagedObjectContext:[[NSApp delegate] managedObjectContext]];
[newInstance setEntityName:entityName];
[newInstance setAutomaticallyPreparesContent:YES];
[newInstance setSelectsInsertedObjects:YES];
[newInstance setAvoidsEmptySelection:YES];
[newInstance setAlwaysUsesMultipleValuesMarker:YES];
NSFetchRequest *dontGobbleRequest = [[[NSFetchRequest alloc] init] autorelease];
//configure the request with fetchLimit and fetchOffset an' all that
NSError *err;
if ([newInstance fetchWithRequest:dontGobbleRequest merge:YES error:&err] == NO) {
//better check docs whether merge:YES is what you want
if(*error && err) {
*error = err;
}
return nil;
}
return newInstance;
}
You'll have to do some research into the various possibilities and configurations, but you get the picture.
Dear community.
I was find a trouble for using a core data. Here is description:
From my AppDelegate i called my own class:
InitUpdateIXC *initAndUpdate = [[[InitUpdateIXC alloc] init] autorelease];
[initAndUpdate updateCarrierList:self.managedObjectContext];
Then i using there couple of methods, which update managedObjectContext, insert, add some entities e.t.c.
In this case i find limitation to using predicate twice per method:
First using working fine, and i seen results inside request:
NSFetchRequest *requestDestinationsForSale = [[NSFetchRequest alloc] init];
[requestDestinationsForSale setEntity:[NSEntityDescription entityForName:#"DestinationsListForSale"
inManagedObjectContext:managedObjectContext]];
[requestDestinationsForSale setPredicate:[NSPredicate predicateWithFormat:#"carrier.name like %#",carrierName]];
NSArray *destinationsForSale = [managedObjectContext executeFetchRequest:requestDestinationsForSale error:&error];
Inside the loop around MO:
for (NSManagedObject *destinationForSale in destinationsForSale)
{
for (NSManagedObject *code in [destinationForSale valueForKey:#"codesvsDestinationsList"])
{
i try to make new fetchRequest:
NSFetchRequest *requestDestinationWeBuy = [[[NSFetchRequest alloc] init] autorelease];
[requestDestinationWeBuy setEntity:[NSEntityDescription entityForName:#"DestinationsListWeBuy"
inManagedObjectContext:managedObjectContext]];
NSError *error = nil;
[requestDestinationWeBuy setPredicate:[NSPredicate predicateWithFormat:#"carrier.name like %#",carrierName]];
NSArray *destinationWeBuyList = [managedObjectContext executeFetchRequest:requestDestinationWeBuy error:&error];
ops... NSArray is empty...
if i do a same when i call method from AppDelegate:
[initAndUpdate updateRoutingTable:self.managedObjectContext];
It's a same class, same method, just called from main AppDelegate and little bit changed for using a just managed context, everything working fine.
Looks like managedObjectContext have final updates only when we leave class methods, which make updates.
Any comment will appreciated.
In your first fetch you are fetching on the entity DestinationsListForSale but in the second you are fetching on the entity DestinationsListWeBuy. The simplest explanation is that the same predicate does not produce the same result when applied to different entities.
Depending on the specifics of both the entities and the data being persistent at any one time, the same predicate will produce different outcomes when applied against different entities.
Indeed, that would be the expected behavior.