How to stock NSString in Core Data? - iphone

I have a model that follows this:
Then I want to stock a city from a UITableView. The problem is, that I want to hold them in the iPhone (Database) until it reach 10, after that it erases the first and adds the last. I have the idea, but I can't just reach to add anything and i'm confused.
When I click a city, it pushes to the next view sending from a response JSON the id and the name of the city.. Thats ok. But I want to store those in order to make the same call but from another UITableView (under it) So it's like the "Last cities searched" something lik that.
I want to save the id,name and after that load it in the other tableView showing only the name. With that i'm Ok, but I can't reach to make the stock happend.
Code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailTaxi *detailView = [[DetailTaxi alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];
NSString *nomville = [[_jsonDict objectAtIndex:indexPath.row] objectForKey:#"label"];
NSString *idVille = [[_jsonDict objectAtIndex:indexPath.row] objectForKey:#"id"];
detailView.title = nomville;
detailView.idVille = idVille;
NSLog(#"Valor: %#", nomville);
NSLog(#"Valor: %#", idVille);
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSString *insert = [[NSString alloc] initWithFormat:#"%#,%#",idVille,nomville];
NSManagedObject *newVille;
NSArray *insertVilles = [insert componentsSeparatedByString:#","];
for(NSString *insert in insertVilles) {
newVille = [NSEntityDescription insertNewObjectForEntityForName:#"Ville" inManagedObjectContext:context];
[newVille setValue:[insertVilles objectAtIndex:0] forKey:#"id"];
[newVille setValue:[insertVilles objectAtIndex:1] forKey:#"nom"];
}
[self.navigationController pushViewController:detailView animated:YES];
}

Just add a new attribute of type NSDate which you set to the current date upon creating a new entry. Once you retrieve the cities again, use a sort descriptor to sort the cities by the time they were saved and use a fetch limit.
If deleting the previous cities is necessary, the date attribute will prove useful as well.

Related

grab text from NSMutableArray tableview cell

I don't understand why the code isn't working, and nothing I found seems to be working. So I've come here for help. Ultimately, I want to be able to send my link to Safari whenever I click on the "View" button, and I want the link to be copied whenever I click on the "Copy" button.
Here's the code (under " - (void)viewDidLoad "):
NSMutableArray *sites = [[NSMutableArray alloc] initWithObjects:#"http://www.apple.com/", #"http://www.youtube.com/", #"http://maps.google.com/", #"http://ww.google.com/", #"http://www.stackoverflow.com/", nil];
self.cloudsendList = sites;
Here is the code (under " - (IBAction) touchUpInsideAction:(UIButton*)button "):
NSIndexPath* indexPath = [tableView indexPathForCell:sideSwipeCell];
NSUInteger index = [buttons indexOfObject:button];
NSDictionary* buttonInfo = [buttonData objectAtIndex:index];
if ([[buttonInfo objectForKey:#"title"] isEqualToString:#"View"]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat: #"%#", indexPath.row]]];
} else if ([[buttonInfo objectForKey:#"title"]isEqualToString:#"Copy"]) {
NSString *message = indexPath.row;
[UIPasteboard generalPasteboard].string = message;
Just to note, I am able to see the NSMutableArray data on each cell, I just can't grab it. I've also tried to insert "cloudsendList indexPath.row" instead of just "indexPath.row", but it didn't work. I hope this gives you enough information, and any bit of help would be really appreciated. Also, I apologize if I sound kind of noobish; I'm still sort of new to Objective-C programming. Thanks! :)
indexPath.row is an NSInteger, not the text at that location. This means your NSString *message is getting the integer value of the row you are on (0, 1, 2...). Try using that location as an index when pulling from your sites/cloudsendList array.
Ex.
NSString *message = [cloudsendList objectAtIndex:indexPath.row];
UPDATE:
To open the browser, use the same concept.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat: #"%#", [cloudsendList objectAtIndex:indexPath.row]]]];

Pass Core Data results to UILabel

I'm selecting a row from a table. I want to pass the results of that selection to a UILabel on a new View. Do I need an NSFetchRequestController subroutine for the below? I wanted a simpler way to pass the event core data selection to a non-UITableView Controller (just a regular UIViewController).
The 'request' at objectIndexPath below is causing the error.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ReviewController *reviewViewController = [[ReviewController alloc] init];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
Event *selectedEvent = (Event *)[request objectAtIndexPath:indexPath];
reviewViewController.event = selectedEvent;
[self.navigationController pushViewController:reviewViewController animated:YES];
[reviewViewController release];
}
You don't need a new fetched results controller. You just pass the managed object associated with the selected tableview row to the next controller. You are getting the error because you haven't performed a fetch and in any case a fetch request does not have a objectAtIndexPath method.
If you have a fetched results controller for the tableview, you find the selected object with:
reviewViewController.event =[[self.fetchedResultsController fetchedObjects] objectAtIndex:index.row];

How to store array of NSManagedObjects in an NSManagedObject

I am loading my app with a property list of data from a web site. This property list file contains an NSArray of NSDictionaries which itself contains an NSArray of NSDictionaries. Basically, I'm trying to load a tableView of restaurant menu categories each of which contains menu items.
My property list file is fine. I am able to load the file and loop through the nodes structure creating NSEntityDescriptions and am able to save to Core Data. Everything works fine and expectedly except that in my menu category managed object, I have an NSArray of menu items for that category. Later on, when I fetch the categories, the pointers to the menu items in a category is lost and I get all the menu items. Am I suppose to be using predicates or does Core Data keep track of my object graph for me?
Can anyone look at how I am loading Core Data and point out the flaw in my logic? I'm pretty good with either SQL and OOP by themselves, but am a little bewildered by ORM. I thought that I should just be able to use aggregation in my managed objects and that the framework would keep track of the pointers for me, but apparently not.
NSError *error;
NSURL *url = [NSURL URLWithString:#"http://foo.com"];
NSArray *categories = [[NSArray alloc] initWithContentsOfURL:url];
NSMutableArray *menuCategories = [[NSMutableArray alloc] init];
for (int i=0; i<[categories count]; i++){
MenuCategory *menuCategory = [NSEntityDescription
insertNewObjectForEntityForName:#"MenuCategory"
inManagedObjectContext:[self managedObjectContext]];
NSDictionary *category = [categories objectAtIndex:i];
menuCategory.name = [category objectForKey:#"name"];
NSArray *items = [category objectForKey:#"items"];
NSMutableArray *menuItems = [[NSMutableArray alloc] init];
for (int j=0; j<[items count]; j++){
MenuItem *menuItem = [NSEntityDescription
insertNewObjectForEntityForName:#"MenuItem"
inManagedObjectContext:[self managedObjectContext]];
NSDictionary *item = [items objectAtIndex:j];
menuItem.name = [item objectForKey:#"name"];
menuItem.price = [item objectForKey:#"price"];
menuItem.image = [item objectForKey:#"image"];
menuItem.details = [item objectForKey:#"details"];
[menuItems addObject:menuItem];
}
[menuCategory setValue:menuItems forKey:#"menuItems"];
[menuCategories addObject:menuCategory];
[menuItems release];
}
if (![[self managedObjectContext] save:&error]) {
NSLog(#"An error occurred: %#", [error localizedDescription]);
}
You set a NSArray as to-many relationship object
NSMutableArray *menuItems = [[NSMutableArray alloc] init];
[menuCategory setValue:menuItems forKey:#"menuItems"];
which might cause the trouble.(should throw an exception?) Relationships in CoreData are always unsorted, therefore NSSets. Add a sortIndex property to your entities for ordering.
I had the same issue. There are 2 major problems with using NSSets and Core Data: if you need non-distinct objects and need them ordered. As an example, say you have 2 entities in Core Data: professor and student. The student takes 10 classes for a degree program and you wish to have a (one-to-many) relationship from the student to the professor in order that the classes were taken. Also, the same professor may teach more than one class. This was how I overcame the issue. Create a Binary Data attribute (we'll call it profData) in student and store dictionaries that make it possible to reconstruct the data as needed. Note: don't store an array of professors, since they inherit from NSManagedObject vs. NSObject. That can cause problems. You can bolt on the required methods using a category. In this example, I created a category on Student called ProfList (Student+ProfList.h/m). This keeps the code out of the NSManagedObject subclasses, so if my attributes in Core Data change, I can regenerate the subclasses automatically without wiping out this code. Here is some sample code:
// Student+ProfList.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Student.h"
#import "Professor.h"
#interface Student (ProfList)
- (NSArray *)getStudentsFullList;
- (void)storeStudentsFullList:(NSArray *)fullList;
#end
// Student+ProfList.m
#import "Student+ProfList.h"
#implementation Student (ProfList)
- (NSArray *)getStudentsFullList
{
NSData *storedData = self.profData;
if (!storedData) return nil;
NSMutableArray *fullList = [[NSMutableArray alloc] init];
// Retrieve any existing data
NSArray *arrayOfDictionaries = [NSKeyedUnarchiver unarchiveObjectWithData:storedData];
// Get the full professor list to pull from when recreating object array
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Professor"];
NSSortDescriptor *alphaSort =
[[NSSortDescriptor alloc] initWithKey:#"name"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)];
[fetchRequest setSortDescriptors:#[alphaSort]];
NSSet *allProfessors = [NSSet setWithArray:[context executeFetchRequest:fetchRequest error:nil]];
for (NSDictionary *dict in arrayOfDictionaries) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name LIKE %#", [dict objectForKey:#"name"]];
NSSet *filteredSet = [allProfessors filteredSetUsingPredicate:predicate];
Professor *newProfessor = [filteredSet anyObject];
newProfessor.index = [dict objectForKey:#"index"];
[fullList addObject:newProfessor];
}
return fullList;
}
- (void)storeStudentsFullList:(NSArray *)fullList
{
NSMutableArray *encodedList = [[NSMutableArray alloc] init];
for (Professor *professor in fullList) {
[encodedList addObject:#{#"index" : #([encodedList count]), #"name" : professor.name}];
}
NSArray *encodedArray = [NSArray arrayWithArray:encodedList];
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:encodedArray];
self.profData = arrayData;
}
#pragma mark - Core Data
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
#end
You store a local variable in a view controller, then send this message to the student instance to get the list and save it locally for use in a table view or whatever.

iPhone Core Data problems

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
BlogRssParser *blogRss = [[BlogRssParser alloc] init];
[blogRss setSelectedObject:selectedObject];
RssFunViewController *rssFun = [[RssFunViewController alloc] initWithNibName:#"RssFunViewController" bundle:nil];
[self.navigationController pushViewController:rssFun animated:YES];
[rssFun release];
}
This is my code so when the user taps the row, its supposed to take the value from the row and insert it into here:
NSString *terms = [[[self selectedObject] valueForKey:#"data"]description];
NSLog(#"%#", terms);
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://news.search.yahoo.com/rss?ei=UTF-8&p=%#&fr=news-us-ss", terms]];
But "terms" is showing up as (null) in the log? Not the value of the clicked row
I see, that u used some codes, I posted here for you. But you shouldnt just copy and paste it.
In my code selectedObject is not a member, as it is absolutely not necessary.
This line
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
points to a non-member variable
while
[self selectedObject]
points to a member — a totally different thing.
edit
Is the second part in the TableViewContoller or in the DetailedView?

UITableView grouping sections

I have a UITableView that's populated using core data & sqlite.
I'd like to have sections grouped in the UITableView based on an attribute from the database table.
e.g If i had a category field in the database table called "type", what would be the best way of sectioning that data out?
I've seen examples using arrays, but I'm getting stuck with the core data. all the data is currently displayed from the database and I'd like to section it out somehow.
thanks in advance.
If you are using an NSFetchedResultsController to fetch your results and connect them to your UI it's pretty easy. Just set the sectionNameKeyPath: parameter of the initWithFetchRequest call to NSFetchedResultsController.
In this example, which is only slightly modified from the class reference for NSFetchedResultsController I have defined a key path that will use the section named "group" as the section title. Thus, if you have rows in your database that have a group set to "Cats" and other rows with a group set to "Dogs" your resulting table view will have 2 sections - one for cats and one for dogs.
NSManagedObjectContext *context = <#Managed object context#>;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Configure the request's entity, and optionally its predicate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"<#Sort key#>" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:#"groups"
cacheName:#"<#Cache name#>"];
[fetchRequest release];
NSError *error;
BOOL success = [controller performFetch:&error];
For more information about key-paths you have to search for the key path documentation in the Xcode doc set. For simple cases though, it's just the name of an attribute of your returned objects.
I found an array to be really useful when using sections. Take a look at my example code
Sort friends (From CoreData)
NSMutableArray* unsortedFriends = [appDelegate.core.serviceManager.storageManager getFriendList];
for(ELMUser* user in unsortedFriends) {
if ([user.friendshipConfirmed boolValue]) {
if (![user.localDeleted boolValue]) {
[friendList addObject:user];
}
} else {
if (![user.localDeleted boolValue]) {
[friendListUnconfirmed addObject:user];
}
}
}
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:friendList];
[listOfItems addObject:friendListUnconfirmed];
Display Cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
NSMutableArray *subArray = [listOfItems objectAtIndex:indexPath.section];
ELMUser* user = (ELMUser*)[subArray objectAtIndex:indexPath.row];
....