array of NSManagedObjectID from NSFetchedResultController - ios

I have a data set displayed in a UICollectionviewController, which I access using [fetchedResultsController objectAtIndexPath:indexPath]
Using a segue, I move onto a modal scrollview+uipageController, where each data is displayed one after the other. The problem is to access each of them individually, as the view controller does not hold the fetch request. I'm thinking passing an array of object IDs, so that each page can fetch the associated data, from the data store.
my question is: given the fetchresultController, in the UICollectionviewController I'm seguing from, is there a way to quickly create the array of Object IDs, or do I have to loop through each managedObject, obtain their ManagedObjectID, and fill it into the array ?

You can use valueForKey to get all object IDs from an array of managed objects:
NSArray *objects = [fetchedResultsController fetchedObjects];
NSArray *objectIDs = [objects valueForKey:#"objectID"];
(Generally, sending valueForKey: to an array of objects applies valueForKey: to each object of the array, and returns an array of the results.)
Remark: When working with object IDs, keep in mind that these can change, see e.g. the objectID documentation:
Important If the receiver has not yet been saved, the object ID is a
temporary value that will change when the object is saved.

Related

How to Store User Entered Details and Get It Back in ios?

How to Store user entered details and Get it Back in ios?
I had Following TextFields :
UserName,Email, Re-enter Email id, Phone,
State,Address,Localityand Pincode.
I want to store this Details in Current viewController locally and
display this details in Next ViewController....
How many Ways I can Store and Fetch the Details, Does anyone know where I can find more information about this?
Do you want to keep user Info persistent(1) or you need this data just to represent it and send to email(2)?
1.If you need to save user info in persistent store using Core Data you have to create entity named 'User' with your attributes (Name, middle name , lastname, username,email, re-enter email id, phone, state, address,locality and pincode) - all this fields can be A String type. Than by the help of 'Editor' tab you should create NSManagedObject subclass for your entity. Than in your VC with textFields you need to fill these data for properties of User instance and save it. And than you can retrieve where you want and display for user.
2.If you need user info just to display and send to email you can make it simpler by using NSUserDefaults for example:
//to save
[[NSUserDefaults standardUserDefaults] setObject:textFieldName.text forKey:#"name"];
//to get data
[[NSUserDefaults standardUserDefaults] valueForKey:#"name"];
Or if there is a need to keep this info all the time and you need it just for one app launch session - just set ViewControllerWhereYouWantToPresentInfo's public properties by text property value of textFields.
I would suggest you to create variables and store your data there. Once you are ready to go to the next view controller , you can pass the data to your next view controller in this fashion
let nextVC = self.storyboard!.instantiateViewControllerWithIdentifier("NextVCStoryBoardId") as! NextVCViewController
nextVC.variable1 = variable1 //variable1 is in currentVC
nextVC.variable2 = variable2 //variable2 is in currentVC
and so on...
You can then push to nextVC with this code
self.navigationController!.pushViewController(nextVC, animated: true)
In nextVC , you make an action for button to send the data to mail.
If the user data is properly stored in core data, you can retrieve it with either a NSFetchedResultsController (FRC) or a simple NSFetchRequest. In both cases you would create a NSFetchRequest for your 'user' entity and assign it an NSPredicate. The predicate is defined similar to a SQL query. The NSFetchRequest will retrieve any managed objects that match the predicate.
You might consider though passing these arguments into the second viewController as either arguments or as public properties, rather than fetching and storing them in CoreData. CoreData is great for persisting data on disk when it needs to be query-able (like and SQL database). It's also useful when the UI needs to be frequently updated to reflect changes in the persisted data. You can use NSFetchedResultsContoller to monitor changes to your data mode and automatically notify the UI layer of those changes.
Example using an NSFetchRequest, its the simplest way to do what you are asking. It assumes you have an entity called "UserDetails" and it has a property called "user_id" to identify a specific user
// A pointer to your main thread context, since you will be using this info to
// populate data on the UI. I typically use a singleton pattern to access my
// managed object context
NSManagedObjectContext *context = [DBController sharedInstance].mainManagedObjectContext;
// Create the fetch request
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"UserDetails"];
// Assign the predicate
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"user_id = %#",<the_users_id>];
// Execute the fetch request on the main thread managed object context
NSError *error = nil;
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
UserDetail *detail = [object firstObject];

-[__NSCFDictionary Title]: unrecognized selector sent to instance

I have created an application that populates a table from JSON data I pull from my local host. I am able to search through this data using a search bar and have added a button to add the rows to another table which I am using a library for a users favourite objects. So now that Ive this all working I'm trying to create a detail view that when a user clicks on a row in the table they are brought to a new view controller and then they can view the full details of the object as the rows in the initial table only have the title and author listed in each row.
I have made the Segue and created the view controller ect and when I try to populate a few UILabels on the detaiViewController I get a error:
Maybe papers dictionary store others NSDictionary, not Paper object. When you parse a JSON, it will parse to iOS SDK class, such as [] parse to NSArray, "" parse to NSString, {} parse to NSDictionary.
So, I guess your JSON will parse to an array of dictionary. It cannot return a Paper for you. You have to assign values in each dictionary to one your Paper, and put it in a NSArray of Paper.
Change:
self.Title.text = self.paper.Title;
to:
self.Title.text = self.paper[#"Title"];
Use awakeFromNib instead of viewDidLoad
NSMutableArray *locations = [[NSMutableArray alloc] init];
_papers = [json objectForKey:#"Papers"];
You are populating the locations array from retrieving elements from _papers. Actually _papers holds list of NSDictionaries and when in prepareForsegue you just get an element from _papers which is a dictionary so thats why it is giving error. You have to store this locations array and retrieve elements from it because you are parsing the json into paper in the loop and putting it in locations hope it helps.

iOS, Why is fetchedResult automatically updating itself when i modify the contents of MutableArray created from it?

I'm making use of FetchedResultController stuff for my tableViewController, once i get the results, I'm creating an NSArray with the fetched objects
self.sortedArray = [self.fetchedResultsController fetchedObjects];
Now, I get all the results as desired but then when I make changes to the objects within self.sorted array, say..
Product *product = [self.sortedArray objectAtIndex:indexPath.row];
product.date = newDate;
bla bla blaaaa
note: product is an instance of the entity that was fetched.
Now, when i try to access the old, unmodified object from the fetched result,
Product *actualProduct = [self.fetchedResultsController objectAtIndexPath:indexPath];
it gives me the updated version. I'm not saving context before this.
Also, i cannot use
[self.moc refreshObject:product mergeChanges:NO];
because different fields of the same object is updated using other controls, so i need to track all changes to same object and also need to have reference to the original one.
I tried the same by creating a separate NSMubtableArray, and even with NSArray.. gives me the same result.
When you store the fetchedObjects in an array, you are just storing a reference to the array. The array stores references to the objects it has. So when you modify these objects, the array will be pointing to the modified object. If you don't want to change the original object, do something like this or create a brand new Product object and copy the values from [self.sortedArray objectAtIndex:indexPath.row] and modify it.
Product *product = [[self.sortedArray objectAtIndex:indexPath.row] copy];
product.date = newDate;
...
You might have to override copyWithZone:(NSZone *)zone of NSObject if your custom object is elaborate, like it has more objects within. Read more about copying objects here https://developer.apple.com/library/ios/documentation/general/conceptual/devpedia-cocoacore/ObjectCopying.html
Because it is referencing to the same object. If you want to modify the MO you can create another MOC whose its parent context is the one you don't want to modify (yet.) Then, when you're ready to make changes, you save that child context which will propagate its changes to the parent context.

Create a copy of a NSManagedObject

I need to temporarily store the content of a NSManagedObject into a dictionary. Because core data has its own memory management procedures, I don't want to keep any strong pointers to the NSManagedObject's fields, only the values are of interest at this point (values are passed between view controllers, the MOCs are different). I can't create weak pointers either because I want to control when the memory reclaim is done.
I tried a few things, all failed or did not fit the purpose.
a duplicate [[myNSMO alloc] initWithEntity:[NSEntityDescription entityForName:entity inManagedObjectContext:myNSMO.managedObjectContext] insertIntoManagedObjectContext:nil];
It's working, but does not fit into my app design (without getting into details)
generate a NSDictionary from the NSManagedObject, using [myNSMO dictionaryWithValuesForKeys:<#(NSArray *)#>]. That's not ok because it returns a dictionary with the addresses of the NSManagedObject fields.
create a NSDictionary populating each key-value using a copyWithZone, like this
[myDictionary setObject:[myNSMO.field copyWithZone:nil] forKey:#"Key"];
Doesn't work either, I still get the field address...
Manually enter each field with
[myDictionary setObject:[NSString stringWithFormat:#"%#",myNSMO.field ] forKey:#"Key"];
It's fine this time, I do get new memory allocation. But that's highly time consuming to code this manually...
Any chance that someone found clever way to do that? the reason option 1) did not work is because I use the dictionary as a queue. I first store a copy of the object, then pop the entry out when required. A copy of that particular dictionary entry is then returned to the asking method. The problem is that I can't create a copy of an NSManagedObject that was created using [[...] insertIntoManagedObjectContext:nil];
Any solutions?
It's safe to keep strong pointers to the fields of a managed object in most senses — relationships are special but the actual Foundation objects of dates, strings and numbers are ordinary objects that'll stay in memory if you have a strong reference.
That being said, to create a dictionary copy containing all the properties of an entity you could do something like:
NSArray *properties = [[object entity] properties];
NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary dictionary];
for(NSAttributeDescription *attribute in properties)
{
// we want only actual attributes, not relationships
// or fetched properties
if([attribute isKindOfClass:[NSAttributeDescription class]])
{
[dictionaryRepresentation
setObject:[object valueForKey:attribute.name]
forKey:attribute.name];
}
}
So you're using the fact that managed objects expose a description of their entities which includes a list of properties, whittling those properties down to just the attributes, then using key-value coding to fetch the current value of each property and finally inserting it into the dictionary.
If for some reason you did want copies of the properties — though, as I say, there's absolutely no reason to do so — you'd copy (and autorelease if you're not using ARC) each property when inserting it into the dictionary.

RestKit & iOS, JSON, Rails - How to map instances of class into a Dictionary/hash to be easily selected by unique identifier

I have a basic iOS app that interfaces with a Rails app. The idea here is to load all channel objects from my RESTful /channels.json route set up in Rails.
I want to load all of the Channel objects into an NSDictionary in Xcode so that they can easily be identified using the Channel object's ID generated by ActiveRecord -- something along the lines of [dictionary objectForKey:#"1"]
I've had no trouble loading all the Channel objects into an NSArray, but getting them to load into an NSDictionary is proving tough. I've implemented RestKit's didLoadObjectDictionary delegate method, and have set up my JSON response as follows: https://gist.github.com/2504664
I believe I have my mapping set up incorrectly. The mapping for the Channel objects is set up as follows: https://gist.github.com/2504667
When the didLoadObjectDictionary method is called, the objects NSDictionary contains 0 key/value pairs.
How do I go about loading all Channel objects into an NSDictionary so that I can easily refer to them using objectForKey as explained above?
You can still fetch things out of the nsarray using a predicate:
[someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"id = %#", someId]];
It returns another NSArray (which should have one object).
Alternatively you could use restkit's coredata mappings then simply fetch the object by ID out of core data.

Resources