Having trouble adding objects to NSMutableArray - objective-c

Im having truble adding objects to my 2 NSMutableArrays. The data comes from a database and I know that my parsing is correct because I get valid outputs when I use the NSLog. However I can't figur out how to add the 2 different objects to my 2 different NSMutableArrays. Here is my code
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
allDataDictionary = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
feed = [allDataDictionary objectForKey:#"feed"];
arrayOfEntry = [feed objectForKey:#"entry"];
for (NSDictionary *dictionary in arrayOfEntry) {
NSDictionary *title = [dictionary objectForKey:#"title"];
NSString *labelTitle = [title objectForKey:#"label"];
[arrayLabel addObject:labelTitle];
NSDictionary *summary = [dictionary objectForKey:#"summary"];
NSString *labelSummary = [summary objectForKey:#"label"];
[arraySummary addObject:labelSummary]; //This line makes the application crash
}
}
for some reason when I want to add labelSummary to arraySummary I get this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Any help is appreciated.

Your parsing is indeed correct. However, when the parser comes across an empty field it returns nil. The problem is the that NSArrays cannot accept nils, because nil is not an object, it's equivalent to 0. Therefore, you most add an object. This the role of NSNull.
Must test to see if the parser returns nil, and if so add [NSNull null].
NSString* labelSummary = [summary objectForKey:#"label"];
[arraySummary addObject:(labelSummary!=nil)?labelSummary:[NSNull null];

The error message tells you that one of the objects you are trying to add to the array is nil.
You have to replace
[arrayLabel addObject:labelTitle];
with
if (labelTitle != nil) {
[arrayLabel addObject:labelTitle];
}
and
[arraySummary addObject:labelSummary];
with
if (labelSummary != nil) {
[arraySummary addObject:labelSummary];
}
If you really need to include a nil object, then use NSNull.

Related

Viewing data retrieved from core data stored in an NSArray

I have an iPad app where data is stored in core data. I have used the following code to retrieve the data from the Observations entity which appears to run without any problems and the count of observationList is correct.
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Observations"];
NSError *error = nil;
observationList = [[NSArray alloc]init];
observationList = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
However when I try to access the data with the array - for example:
NSLog(#"%#", [[observationList objectAtIndex:0] objectForKey:#"obsDate"]);
It throws an error
reason: '-[Observations objectForKey:]: unrecognized selector
obsDate exists in core data. Can anyone see what I am doing wrong?
NSManagedObject does not implement objectForKey:, you should be using valueForKey: instead. Your code compiles because the array returns an id so the compiler just has to trust that the method you're calling on it will exist at runtime.
Aside: this line is pointless
observationList = [[NSArray alloc]init];
Because you throw away that array instance on the next line.

How to initialize, pass argument, and check error condition using NSError**

Xcode 4.3
I've read the SO questions on NSError**, so I wrote a simple test program that uses a slightly different syntax recommended by Xcode 4.3 (see __autoreleasing below), so I'm not 100% sure if this is correct, although the code does appear to function properly. Anyway, just a simple file reader, prints an error if the file can't be found.
Questions
Would like to know if the NSError initialization, argument passing using &, and error condition checking are correct.
Also, in the readFileAndSplit.. method, I noticed a big difference between if(!*error) and if(!error), in fact, if(!error) does not work when no error condition is raised.
File Reading Method w/Possible Error Condition
-(NSArray*) readFileAndSplitLinesIntoArray:(NSError *__autoreleasing *) error {
NSString* rawFileContents =
[NSString stringWithContentsOfFile:#"props.txt"
encoding:NSUTF8StringEncoding
error:error
NSArray* fileContentsAsArray = nil;
if(!*error)
fileContentsAsArray =
[rawFileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
return fileContentsAsArray;
Caller
SimpleFileReader* reader = ...
NSError* fileError = nil;
NSArray* array = [reader readFileAndSplitLinesIntoArray: &fileError];
if(fileError){
NSLog(#"Error was : %#, with code: %li",
[fileError localizedDescription],(long)[fileError code]);
}
There are a couple of issues.
First, As per Apple's Error Handling Programming Guide, you should be checking a method's return value to determine whether a method failed or not, and not NSError. You only use NSError to get additional error information in the event that the method failed.
E.g.:
NSArray* fileContentsAsArray = nil;
NSString* rawFileContents = [NSString stringWithContentsOfFile:#"props.txt"
encoding:NSUTF8StringEncoding
error:error];
if (rawFileContents)
{
// Method succeeded
fileContentsAsArray = [rawFileContents ...];
}
return fileContentsAsArray; // may be nil
Second, NSError out parameters are typically optional and may be NULL. But if you pass a NULL error variable into your method it will crash on this line:
if (!*error) {
because you're dereferencing a NULL pointer. Instead, you must always check for NULL before referencing a pointer, like so:
if (error && *error)
{
// Do something with the error info
}
However, if you rewrite the method as indicated above then you won't be accessing the error variable at all.

How to deal with an empty object {} in RestKit

The response I sometimes get from the server is a JSON representing an empty object like this {}
I've read this question/answer over here already, which states I should implement the willMapData delegate function and point the *mappableData somewhere else. The thing is I can't figure out what should I assign to *mappableData so that my app won't crash.
I've tried this
- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData
{
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeJSON];
*mappableData = [parser objectFromString:#"{\"unknownObject\":\"\"}" error:nil];
}
But nevertheless my app crashes with a rather pissing
'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]
Can you help me out?
UPDATE
Turning on RKDebug messages gives me this in the console:
Performing object mapping sourceObject: {
}
and targetObject: (null)
then the code reaches RKObjectMapper.m:
if (mappableData) {
id mappingResult = [self performMappingForObject:mappableData atKeyPath:#"" usingMapping:mappingsForContext];
foundMappable = YES;
results = [NSDictionary dictionaryWithObject:mappingResult forKey:#""];
}
but mappingResult over there comes back nil... so the app crashes when it tries to create an NSDictionary with a nil object.
Break up the assignment into two lines.
SomeDataType *object = [parser objectFromString:#"{\"unknownObject\":\"\"}" error:nil];
if(object){
*mappableData = object;
}else{
// You've got nil, do something with it
}
Now you can check for nil values and take the appropriate action. What that action is depends on the context of the crash.

NSRangeException for empty array except there is an array?

I'm having this problem where I keep getting this error in my console:
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array'
Here is my code for retrieving the data from the XML document:
CXMLDocument *worldweather = [[CXMLDocument
alloc]initWithContentsOfURL:[NSURL URLWithString:[NSString
stringWithFormat:#"http://free.worldweatheronline.com/feed/weather.ashx?q=%#&format=xml&num_of_days=4&key=0ded69e02b171832121504",query]]
options:0 error:nil];
weathercondition = [[[worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil]
objectAtIndex:0] stringValue];
The location that Xcode is using is Williams, CA and the query sent is
Williams+CA
When I plug this into my URL, it works and I get my XML file, but why am I getting this message in my console???
This is driving me crazy. All help would be GREATLY appreciated! Thanks in advance!
Seems that you think that [worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil] is NSArray with at least one object inside the array. This is clearly not the case, and you get an error saying that there is no object at index 0, which means that array is empty.
If you are not sure there is at least one object inside an NSArray do not just call objectAtIndex:0.
You could first check how many elements are there in array and then do the work like:
NSArray *weatherArray = [worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil];
if ([weatherArray count] > 0){
weathercondition = [[weatherArray objectAtIndex:0] stringValue];
}
If you are not sure what you are getting back from the server, see what is in the array:
NSLog(#"%#", weatherArray);
or check how many elements there are:
NSLog(#"elements in Array: %i", [weatherArray count]);
One additional useful thing you can use is for example [weatherArray lastObject], this will always return the last element of the array and will return nil even if the array is empty (it will not crash like objectAtIndex:0)

Put Core Data values in an array

I need to put the values retrieved using a Fetch Request from my core data graph into an array, but not entirely sure how to go about this.
I'm using the following to perform the fetch:
NSString *entityName = #"Project"; // Put your entity name here
NSLog(#"Setting up a Fetched Results Controller for the Entity named %#", entityName);
// 2 - Request that Entity
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
// 3 - Filter it if you want
request.predicate = [NSPredicate predicateWithFormat:#"belongsToProject = %#", _selectedProject];
// 4 - Sort it if you want
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"dateTaken"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)]];
// 5 - Fetch it
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
[self performFetch];
As you can see, i'm filtering the values that come back using an NSPredicate.
How would I get these values into an array and also be able to select individual attributes for the entity once they are in the array, for example the project.description or project.name?
Thanks to Eimantas I've got the objects in an array, however I still need to do two things:
Loop through the array and output the data into some HTML
Individually select attributes from the array, for example, the project description.
I'm using the following for loop to do the first:
for (int i=0; i < [projectListArray count]; i++)
{
NSString *tmp = (NSString *)[projectListArray objectAtIndex:i];
}
However, this is returning the error:
-[Project length]: unrecognized selector sent to instance 0x1b9f20
2012-03-28 10:48:35.160 Project App[3973:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Project length]: unrecognized selector sent to instance 0x1b9f20'
It appears as though i might not be incrementing?
[self.fetchedResultsController fetchedObjects] returns the array of fetched objects.
update
It's better to use fast enumaration, not a for loop:
for (Project *project in projectListArray) {
NSString *projectDescription = [project valueForKey:#"description"];
}
You're getting the exception because you're casting an object to NSString while it's a pointer to (I presume) Project managed object.