Write to dictionary in plist works but then read dictionary from plist returns (null) - nsmutablearray

This is how I am accessing the dictionary in the plist in my viewDidLoad method:
NSString* documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"Level.plist"];
filePath = [documentsDir stringByAppendingPathComponent:fileName];
array = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
dict = [array objectAtIndex:1];
This works fine, I then write to the dictionary like this:
score = [NSString stringWithFormat:#"%d", score.integerValue + 10];
[dict setObject:score forKey:#"Score"];
[dict writeToFile:filePath atomically: NO];
This works fine too, however once I return to this view and try to access the dictionary again in the viewDidLoad method it returns (null) for the dictionary.

This is because you are reading the file as an array, but then when you write it back out again, you're only writing out the dictionary, not the array that contains that dictionary. If you try to use NSMutableArray to read a plist file that has something other than an array at its root, that will result in it returning nil. So if you just replace dict with array in the last line of code, that should do the trick.

Related

iOS - NSPredicate string.length always evaluates to 0 when string starts with arithmetic operators + - * /

I have a simple method that uses NSPredicate to return the number of rows where comments.length > 0.
Problem is, I found that when the Comment column starts with + - * or /, the length property always evaluates to 0, and thus the row is excluded from the count.
I opened the table in SQLite browser and verified the column is a VARCHAR. Using a SQLite query to check string length works just fine (LENGTH(ZComments) > 0), so this must be a CoreData issue.
Here is my function...
-(int)getCommentsCount{
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setIncludesSubentities:YES];
[request setEntity:[NSEntityDescription entityForName:#"InspectionRecord" inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(comments.length > 0)"];
[request setPredicate:predicate];
NSError *err;
NSUInteger count = [managedObjectContext countForFetchRequest:request error:&err];
//count is ALWAYS 0 if 'comments' starts with + - * or / WHYYY???
return count;
}
I was able to work around this by checking for empty/null string instead of using .length, but I'd really like to know why .length fails when the string starts with certain characters.
Has this happened to anyone?
You cannot use Objective-C functions like length in a Core Data fetch request
(and the ".length" part is simply ignored when Core Data translates the fetch request
to a SQLite query). But you can simply compare with an empty string instead:
[NSPredicate predicateWithFormat:#"comment != ''"]
For other queries involving the length, you can use the MATCHES operator with
a regular expression as shown here: CoreData predicate: string property length?.

Xcode - read a file containing NSDate objects

Every time an event is triggered, my app records its date:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [path stringByAppendingPathComponent:#"dates.dat"];
if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
[[NSFileManager defaultManager] createFileAtPath:filename
contents:nil
attributes:nil];
}
NSFileHandle *wHandle = [NSFileHandle fileHandleForWritingAtPath:filename];
[wHandle seekToEndOfFile];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[NSDate date]];
[wHandle writeData:data];
[wHandle closeFile];
I successfully record the events' dates. But now I am having troubles in reading them back. I tried this but the app crashes:
NSData *restore = [NSData dataWithContentsOfFile:filename];
NSArray *date1 = [NSKeyedUnarchiver unarchiveObjectWithData:restore]; // crash here!
I notice that it takes 223 bytes for each NSDate write but that is not officially mentioned. So I am afraid that using 223 bytes as length to parse the file "dates.dat" would cause problems later.
Do you have any ideas to read dates.dat into an NSArray so I can proceed its values?
Thanks in advance
Don't store the dates as arbitrary blocks of data in a file (because you're correct, you shouldn't rely on the number of bytes used for each date).
As a minimum, use a separator character (like a carriage return) so you know which data belongs to each different date. Then you need to parse the file and read in only the appropriate data before you try to unarchive it.

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

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];

How to store last part of string?

I have a string as http://www.google.co.uk/ig/images/weather/partly_cloudy.gif.
I need to save only the partly_cloudy.gif .How do i select obly that part of string?
If you are sure that it represents a path then you can call the lastPathComponent method on it.
Usage
NSString * link = #"http://www.google.co.uk/ig/images/weather/partly_cloudy.gif";
NSLog(#"%#", [link lastPathComponent]);
Use the NSString function componentsSeparatedByString. For example, NSString *url = #"http://www.google.com/1/2/3/test.gif"; NSArray *components = [url componentsSeparatedByString:#"/"]; would give you an NSArray of all strings in between a '/' character.
NSString reference: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html

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