Split NSString into multiple entries to NSMutableDictionary as key/value? - string

Ok, so I have this problem I have been spinning my head around for some time now.
I have a NSString like the following:
NSString* foo = #"Brand: [Ford], Model: [Focus], Color: [black]";
which I would like to transfer into a NSMutableDictionary with Brand, Model, Color as keys and Ford, Focus, black as values (without the brackets [] ), but cannot seem to find any solution to this. How do I come about accomplishing the given scenario?
Edit:
Right now I use
NSArray *stringComponents = [foo componentsSeparatedByString#","];
which gives me an array like
stringComponents = [#"Brand: [Ford]",
#"Model: [Focus]",
#"Color: [black]",];
that I need to get into the syntax proposed by Sam, but how?

NSDictionary is basically just an array that stores the values of the objects and keys, so you'd do something such as:
NSArray *keys = [NSArray arrayWithObjects:#"Brand", #"Model", #"Color", nil];
NSArray *objects = [NSArray arrayWithObjects:#"Ford", #"Focus", #"black", nil];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
forKeys:keys];

Related

NSMutableArray in NSUserDefault

i've a problem with my table!
i use a parsing tableview but when i change view, my table loses data. So i decide to save all data to nsuserdefault; but, here the problem, NSUserDefault warns me:
"Note that dictionaries and arrays in property lists must also contain only property values."
NB: itemsToDisplay is a NSMutableArray and contain title, url, data and summary of parsedItems.
Well, here my code:
self.itemsToDisplay = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"items"] mutableCopy];
if (!self.itemsToDisplay) {
self.itemsToDisplay = [[NSMutableArray alloc] init];
}
self.itemsToDisplay = [[NSMutableArray alloc]init];
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO] autorelease]]];
[[NSUserDefaults standardUserDefaults] setObject:self.itemsToDisplay forKey:#"items"];
[[NSUserDefaults standardUserDefaults] synchronize];
I suppose the problem is setObject:self.itemsToDisplay, but i don't know how solve it.
Thank You guys..
First lets mention that the table cannot lose data because it does not hold any user data. The data is either provided through bindings or through delegation see NSTableViewDataSource in Apples documentation).
Second, the first three assignments to self.itemsToDisplay serve no purpose (unless you have side-effects in the setter) because they are all overridden by the last assignment.
Finally, if this code is already in the delegate then the delegate should be instantiated in your NIB file for the data to survive past a view swap. If your delegate is an object that is instantiated with your view it will also die with it along with all of the data and writing to the user-defaults is a bad idea for what you are trying to achieve. Simply set the delegate to an object whose lifetime is greater than that of both views.
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO] autorelease]]];
//First lets encode it
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.itemsToDisplay];
[userDefault setObject:myEncodedObject forKey:[NSString stringWithFormat:#"sample"]];

CoreData: NSPredicate based on relationships

I'm working on a recipe book right now using Core Data. It's the first time I'm using CoreData and it's working so far, but I'm having some trouble using it in the iPad's split view.
Here's my object model:
http://i621.photobucket.com/albums/tt295/Naosu_FFXI/ObjectModel.png
In my app, steps and ingredients are shown in two tables in the detail view. When I have one recipe, it works as expected. However, the NSFetchedResultsControllers for both tables pulls all the information regardless of what recipe you select. So using an NSPredicate seems to be the most obvious choice.
Here is my code snippet for the NSPredicate:
filteredIngredientsArray = [[NSMutableArray alloc] init];
.... snip ....
//---------- Filtering the ingredients by name ----------
NSError *error = nil;
NSPredicate *ingredientsPredicate = [NSPredicate predicateWithFormat:#"recipe.recipeName == '%#'", selectedName];
[fetchRequest setPredicate:ingredientsPredicate];
NSLog(#"Filtering the INGREDIENTS with this: %#", selectedName);
NSArray *loadedIngredients = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
filteredIngredientsArray = [[NSMutableArray alloc] initWithArray:loadedIngredients];
[self.ingredientTable reloadData];
When I use this, my tables don't get filled period.... so it's definitively working, but not working as I want it to. My NSLog shows that the value of the selectedName variable is the name of the recipe the user taps on.
This has been driving me up the wall and it really bothers me, so any feedback/help would be appreciated.
Remove the single quotes around %# in the predicate format:
[NSPredicate predicateWithFormat:#"recipe.recipeName == %#", selectedName]

NSFetchedResultsController only sorting by 1st sort descriptor

I'm seeing an issue where the NSFetchedResultsController is only sorting by the first NSSortDescriptor in the sortDescriptors array when the data changes. It's really infuriating.
I'm using an NSFetchedResultsController to manage a tableview that is displaying a list of items. These items have an inherent order based on the number property, but a user can favorite an item. Favorited items are displayed at the top of the table view, sorted by the number property.
So, the model looks something like this:
#interface Thing : NSManagedObject
#property (nonatomic, retain) NSNumber *number;
#property (nonatomic, retain) NSNumber *favorite;
#end
#implementation Thing
#dynamic number;
#dynamic favorite;
#end
And I'm configuring my NSFetchedResultsController like so:
- (void)loadView {
...
//
// configure fetched results controller for the things table view
NSFetchRequest *fetchThings = [[NSFetchRequest alloc] init];
fetchChannels.entity = [NSEntityDescription entityForName:NSStringFromClass([Thing class])
inManagedObjectContext:[DataManager sharedInstance].managedObjectContext];
fetchThings.sortDescriptors = #[
[NSSortDescriptor sortDescriptorWithKey:#"favorite" ascending:NO],
[NSSortDescriptor sortDescriptorWithKey:#"number" ascending:YES] ];
_fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchThings
managedObjectContext:[DataManager sharedInstance].managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
NSError *error = nil;
if (![_fetchController performFetch:&error]) {
NSLog(#"error performing fetch! %#", error.localizedDescription);
}
}
When the table is initially loaded, _fetchController correctly sorts the items, so you could end up with something like this:
- Thing: favorite = YES, number = 2
- Thing: favorite = YES, number = 3
- Thing: favorite = NO, number = 1
- Thing: favorite = NO, number = 4
But if you were to un-favorite Thing Number 2, it only sorts by the 1st sort descriptor, and the list looks like this:
- Thing: favorite = YES, number = 3
- Thing: favorite = NO, number = 2
- Thing: favorite = NO, number = 1
- Thing: favorite = NO, number = 4
Has anyone run into this issue or found a work around for it?
Update
It would appear that if I favorite everything, then unfavorite everything, the sorting works itself out. This leads me to believe this could be a faulting issue? Unfortunately, I'm not sure how to work around that, either.
OK, I figured it out, and it's my own fault.
Just because the field represents a BOOL doesn't mean it's actually a BOOL. The favorite field in the Thing model is actually an NSNumber, and as such, has 3 states, #(YES), #(NO), and nil. Once I made sure I was initializing the favorite field properly the sorting started working as expected again.

NSFetchedResultsController predicate NOT filtering part of it (using ANY, IN and BETWEEN in the same fechRequest's predicate)

I've searched a lot here and couldn't find a solution to my situation:
I have a TableViewController that uses NSFetchedResultsController to display data from CoreData.
The model has an entity "Places" that has a to-many relationship called "Types" (and an inverse one, also to-many relationship).
In a first TableViewController I display the objects from entity "types" (each place can belong to more than one type, and one type can have more than one place). When the user taps on a row it calls a new TableViewController that will show objects from entity "Places" related to "Types" using a NSFetchedResultsController.
I know I could just use:
NSSet = [aType valueForKey:#"Places"];
However, I really want to use the NSFetchedResultsController and all its benefits.
Well, at the NSFetchedResultsController accessor method I was able to recreate this relationship by using:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Places"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSDictionary *types = [NSDictionary dictionaryWithObjectsAndKeys:self.theTypes, #"TYPES", nil];
NSPredicate *predicateAny = [NSPredicate
predicateWithFormat:#"ANY types IN $TYPES"];
NSPredicate *predicate = [predicateAny predicateWithSubstitutionVariables:types];
This code works fine as it returns "Places" that are related to the "Types" I want (those were hold inside the property theTypes). I use a property (theTypes), in the TableViewController to hold all "Types" objects one selected at the original tableViewController.
The problem is that the entity "Places" has a property named "distance" that I also need to use as a filter inside the NSPredicate, like this:
NSNumber *radious = [NSNumber numberWithDouble:10000.00];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"distance BETWEEN {0 , %#}", radious];
NSDictionary *types = [NSDictionary dictionaryWithObjectsAndKeys:self.theTypes, #"TYPES", nil];
NSPredicate *predicateAny = [NSPredicate
predicateWithFormat:#"ANY types IN $TYPES"];
NSPredicate *predicate = [predicateAny predicateWithSubstitutionVariables:types];
NSPredicate *thePred = [NSCompoundPredicate andPredicateWithSubpredicates:
[NSArray arrayWithObjects:predicate, pred, nil]];
[fetchRequest setPredicate:thePred];
Here's where the problem occurs: the "distance" filter appears to be simply ignored by the predicate at the fetchRequest. The resulted fetch always has Places that don't match the #"distance BETWEEN {0 , %#} clause.
Can anyone help me figure out what I am missing here?
Thanks a lot!
Daniel
This predicate:
NSPredicate *predicateAny = [NSPredicate
predicateWithFormat:#"ANY types IN $TYPES",
radious];
Doesn't make sense because you don't use the radious variable in this predicate. Not sure if that is the source of the problem but you should clean it up anyway.
This predicate:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"distance BETWEEN {0 , %#}", radious];
... could probably be:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"distance <=%#", radious];
... unless you have the possiblity of a negative radious value. It will be much faster that way.

Search through NSArray for string

I would like to search through my NSArray for a certain string.
Example:
NSArray has the objects: "dog", "cat", "fat dog", "thing", "another thing", "heck here's another thing"
I want to search for the word "another" and put the results into one array, and have the other, non results, into another array that can be filtered further.
If the strings inside the array are known to be distinct, you can use sets. NSSet is faster then NSArray on large inputs:
NSArray * inputArray = [NSMutableArray arrayWithObjects:#"one", #"two", #"one again", nil];
NSMutableSet * matches = [NSMutableSet setWithArray:inputArray];
[matches filterUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[c] 'one'"]];
NSMutableSet * notmatches = [NSMutableSet setWithArray:inputArray];
[notmatches minusSet:matches];
Not tested so might have a syntax error, but you'll get the idea.
NSArray* inputArray = [NSArray arrayWithObjects:#"dog", #"cat", #"fat dog", #"thing", #"another thing", #"heck here's another thing", nil];
NSMutableArray* containsAnother = [NSMutableArray array];
NSMutableArray* doesntContainAnother = [NSMutableArray array];
for (NSString* item in inputArray)
{
if ([item rangeOfString:#"another"].location != NSNotFound)
[containsAnother addObject:item];
else
[doesntContainAnother addObject:item];
}
It would not work because as per document "indexOfObjectIdenticalTo:" returns the index of the first object that has the same memory address as the object you are passing in.
you need to traverse through your array and compare.

Resources