iPhone: Error and error handling confusion in comparison - iphone

NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
if(results == nil){
NSLog(#"No results found");
searchObj = nil;
}else{
if ([[[results objectAtIndex:0] name] caseInsensitiveCompare:passdTextToSearchFor] == 0) {
NSLog(#"results %#", [[results objectAtIndex:0] name]);
searchObj = [results objectAtIndex:0];
}else {
NSLog(#"No results found");
searchObj = nil;
}
}
The code above compares data a user enters to data pulled from a database. If I enter data which is in the database; it works. But if I enter complete gibberish it returns the error below instead of "No results found."
*** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSRangeException> *** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)
The results array being null should be accounted for during the checks in the above code, no?

You are potentially throwing an exception on the following line of code:
if ([[[results objectAtIndex:0] name] caseInsensitiveCompare:passdTextToSearchFor] == 0)
If the array is initialized and has zero elements, you'll pass the nil check, but you'll throw an exception when trying to access any objects within the array itself.
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error can return an empty array. You should use NSArray's count method instead of checking to see if the array is nil.
I recommend you set a breakpoints on objc_exception_throw and [NSException raise] as well to aid you in debugging your applications. Then run a backtrace in gdb to see where the exception is being thrown to further diagnose the real problem.
Chris Hanson has a great writeup on how to accomplish they above located here

Related

NSDictionary Error Handling

I am creating this application but I don't know how to handle the error when there is no value for a given entry in the NSDictionary. Here is the code that I have currently:
NSDictionary *entry = [self entries][indexPath.row];
NSDictionary *text = [self entries][indexPath.row];
NSString *user = entry[#"user"][#"full_name"];
NSString *caption = text[#"caption"][#"text"];
if (caption != nil && entry != [NSNull null] && text != nil && caption != [NSNull null]) {
RNBlurModalView *modal = [[RNBlurModalView alloc] initWithViewController:self title:user message:caption];
[modal show];
}
Here is the error response I receive when I tap on a cell without any caption:
2013-08-08 02:36:57.871 Floadt[5566:c07] -[NSNull objectForKeyedSubscript:]: unrecognized selector sent to instance 0x310b678
2013-08-08 02:36:57.872 Floadt[5566:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull objectForKeyedSubscript:]: unrecognized selector sent to instance 0x310b678'
*** First throw call stack:
(0x2fda012 0x260be7e 0x30654bd 0x2fc9bbc 0x2fc994e 0x5606b 0x1c7a42f 0x1c8c182 0x1c8c394 0x261f705 0x188693c 0x18869ac 0x261f705 0x188693c 0x18869ac 0x1a401d3 0x2fa2afe 0x2fa2a3d 0x2f807c2 0x2f7ff44 0x2f7fe1b 0x2bb77e3 0x2bb7668 0x1778ffc 0x2d2d 0x2c55)
libc++abi.dylib: terminate called throwing an exception
Not clear why entry and text are the same thing. That could be a typo that is causing you issues:
NSDictionary *entry = [self entries][indexPath.row];
NSDictionary *text = [self entries][indexPath.row];
Then, you should really use isEqual for your equality checks (even if only to prevent you getting into bad habits) and check the obtained values (you don't currently check user):
if (![user isEqual:[NSNull null]] && ![caption isEqual:[NSNull null]]) {
Your current checks are mostly redundant - you need to check things before you use them, not afterwards. Checking entry and text must be done earlier. Then check user and caption.
Why you are using two NSDictionary though they store same value [self entries][indexPath.row]?
Change your checking as follow
if (!caption && ([entry isKindOfClass:[NSDictionary class]]) && ([text isKindOfClass:[NSDictionary class]]))

Terminating app due to uncaught exception 'NSRangeException' gives Range or index out of bounds'

I am working on barcode app and getting the location from CLController so its giving location,speed and many other thing so i substring that WithRange and getting exception so please kindly give me the reason and what should i do for this?
Thanks in advance.
- (void)locationUpdate:(CLLocation *)location {
locstr = [location description ];
//NSLog(#"current location is %# ",locstr);
NSString* regexString =#"<(.*?)>";
NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive;
NSError* error = NULL;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:regexString options:options error:&error];
if (error) {
//NSLog(#"error is %#", [error description]);
}
NSArray* results = [regex matchesInString:locstr options:0 range:NSMakeRange(1, [locstr length])];
for (NSTextCheckingResult* result in results) {
resultString = [locstr substringWithRange:result.range];
//NSLog(#"%#",resultString);
//life = [[resultString substringWithRange:NSMakeRange(1)] retain];
resultString =[resultString substringWithRange:NSMakeRange(1,27)];
resultString = [resultString stringByReplacingOccurrencesOfString:#" "
withString:#""];
life = [resultString stringByReplacingOccurrencesOfString:#"+"
withString:#""];
life = [[life substringWithRange:NSMakeRange(0,[life length]-1)] retain];
//NSLog(#"in update %#",life);
}
}
getting this exception
2011-11-23 14:24:58.161 BarCodeApp[2632:707] * Terminating app due
to uncaught exception 'NSRangeException', reason: '
-[NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]: Range or index
out of bounds' First throw call stack: (0x326398bf 0x364a31e5
0x326397b9 0x326397db 0x3783846b 0x37838a11 0x37af 0xbe73 0x3548f5df
0x3548ef81 0x3548962f 0x3260db31 0x3260d15f 0x3260c381 0x3258f4dd
0x3258f3a5 0x37cd0fed 0x30eda743 0x2337 0x22b8) terminate called
throwing an exceptionProgram received signal: “SIGABRT”. Data
Formatters temporarily unavailable, will re-try after a 'continue'.
(Can't find dlopen function, so it is not possible to load shared
libraries.)
dito Aadhira
The app could also crash at
NSMakeRange(1, [locstr length])
You define a range from 1 to [locstr length] there while [locstr length] must be [locstr length]-1.
The string "NSMakeRange" has a length of 11 characters. So, its array index range is is 0-10. Covering your code, the range would be 1-11 as you start at 1 and stop at 1+10=11.
resultString =[resultString substringWithRange:NSMakeRange(1,27)];
Are you sure the resultString length is greater than 27? By any means if it is less than 27, it will crash. It seems the app crashes there. May be in some other places also where you have used NSRange.
Enable NSZombie to get where exactly the app crashes.
Why you're parsing the [CLLocation description] instead of using the properties, like location, accuracy, etc? The description is not supposed to be used like this.

Core Data unresolved error on save

I'm getting an error when saving my core data context, here is the log:
Unresolved error Error Domain=NSCocoaErrorDomain Code=134030 "The operation couldn’t be completed. (Cocoa error 134030.)" UserInfo=0x1937a0 {NSAffectedStoresErrorKey=(
"<NSSQLCore: 0x156410>"
), NSUnderlyingError=0x181a60 "The operation couldn’t be completed. (Cocoa error 4.)", NSFilePath=/var/mobile/Applications/appid/Documents/appname.sqlite}, {
NSAffectedStoresErrorKey = (
"<NSSQLCore: 0x156410>"
);
NSFilePath = "/var/mobile/Applications/appid/Documents/appname.sqlite";
NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=4 \"The operation couldn\U2019t be completed. (Cocoa error 4.)\" UserInfo=0x181a30 {NSUnderlyingError=0x108ab0 \"The operation couldn\U2019t be completed. No such file or directory\"}";
}
I receive this error after removing and deleting an object:
[productList removeMProductObject:product];
[[delegate managedObjectContext] deleteObject:product];
[delegate saveContext];
I also noted that i also receive the error for the following scenarios(debugging):
1.
[productList removeMProductObject:product];
[delegate saveContext];
2.
[[delegate managedObjectContext] deleteObject:product];
[delegate saveContext];
3.
[[delegate managedObjectContext] deleteObject:product];
[productList removeMProductObject:product];
[delegate saveContext];
4.
[[delegate managedObjectContext] deleteObject:product];
[delegate saveContext];//error
[productList removeMProductObject:product];
[delegate saveContext];
5.
[productList removeMProductObject:product];
[delegate saveContext];//error
[[delegate managedObjectContext] deleteObject:product];
[delegate saveContext];
At times, i may pass around either the productList or a product object (both of type NSManagedObject) to other controllers, always using assign in the property and never retain. productList is an object which may contain many product objects.
I am able to create new objects(NSManagedObject), but when it comes to deleting them i get the error mentioned above. When running the application in the simulator i keep a close eye on the sqlite file. after attempting to delete an object(code above), i notice the .sqlite file is removed.
I have created a few Core Data iphone applications with no problem but i seem to be having an issue here. i don't believe i am doing anything out of the ordinary but perhaps i am missing a small detail, but i don't know what!
Why is my .sqlite file being deleted and resulting in this error message on save?
How can i find a more useful error message so i can determine the cause of this error?
Found the problem, but i'm not sure why it fixes it:
Before i would delete/remove the object i would delete the image associated with it(stored in the document's directory).
The image by default has no value(nil), but i would attempt to delete it anyway:
NSError *deleteError = nil;
[[NSFileManager defaultManager] removeItemAtPath:[DOCUMENTS_DIRECTORY stringByAppendingPathComponent:product.mPictureName] error:&deleteError];
#ifdef DEBUG_MODE
if(deleteError) {
NSLog(#"Error deleting image: %#", [deleteError description]);
}
else {
NSLog(#"Image %# deleted.", product.mPictureName);
}
#endif
if i instead do a nil check before attempting to remove the image like this, i get no error when i delete the managed object itself:
NSString *imageName = product.mPictureName;
if(imageName) {
NSError *deleteError = nil;
[[NSFileManager defaultManager] removeItemAtPath:[DOCUMENTS_DIRECTORY stringByAppendingPathComponent:imageName] error:&deleteError];
#ifdef DEBUG_MODE
if(deleteError) {
NSLog(#"Error deleting image: %#", [deleteError description]);
}
else {
NSLog(#"Image %# deleted.", imageName);
}
#endif
}
...
//delete NSManagedObject and save
i guess attempting to access the product's picture when it is nil makes it all invalid.
I had a similar issue that's worth reporting for any poor shmo that gets caught up in this issue. In my case I had a table view controller that handled row deletions by deleting the corresponding data from the data model. When I used the remove##ObjectName##Object method (stubbed out by the auto-generated NSManagedObject subclass), I would get an error similar to the one you reported.
When I instead used NSManagedObjectContext: deleteObject I didn't have a problem saving the context. But, I observed an exception being thrown with no indication of reason from the console.
It turns out the tableView method canEditRowAtIndexPath: was being called for the row corresponding to the newly deleted object. It was clear my row count needed to be updated prior to the OS calling this method. But, I don't care. I simply check to see whether the size of my array of managed objects can be indexed by the indexPath row.
if([managedObjSet.objects count] > indexPath.row) {
ManagedObject* obj = [managedObjectArray objectAtIndex:indexPath.row];
return ([obj.anotherManagedObjSet count] ==0);
}

NSCFArray length]: error, array regex

StringReply = [[NSString alloc] initWithData:dataReply encoding:NSUTF8StringEncoding];
//Regex Out Artist Name
//NSString *regEx = ;
NSArray *iTunesAristName = [stringReply componentsMatchedByRegex: #"(?<=artistname\":\")([^<]+)(?=\")"];
if ([iTunesAristName isEqual:#""]) {
NSLog(#"Something has messed up");
//Regex Out Song Name
}else{
NSLog(iTunesAristName);
}
NSLog(iTunesAristName);
[stringReply release];
I just keep getting this error ?
2010-09-29 21:15:16.406 [2073:207] *** -[NSCFArray length]: unrecognized selector sent to instance 0x4b0b800
2010-09-29 21:15:16.406 [2073:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFArray length]: unrecognized selector sent to instance 0x4b0b800'
2010-09-29 21:15:16.407 [2073:207] Stack: (
please help its driving me crazy
The first argument to NSLog is supposed to be a format string. You're passing an NSArray. When the function tries to treat your array as a string, you get that error. Instead, use NSLog(#"%#", iTunesAristName);.
Chuck has answered your question, but I've noticed something else that is problematic.
NSArray is an array, not a string, so [iTunesArtistName isEqual:#""] will never return true, because they are different classes. Even if iTunesArtistName was a string, it should be compared using the isEqualToString: method, not isEqual:.
If you want to extract only the artist's name, you might be able to do this:
NSArray *matches = [stringReply componentsMatchedByRegex: #"(?<=artistname\":\")([^<]+)(?=\")"];
if ([matches count] == 0)
{
NSLog(#"Could not extract the artist name");
}
else
{
NSString *iTunesArtistName = [matches objectAtIndex:0];
NSLog(#"Artist name: %#", iTunesArtistName);
}
I see you're using RegexKitLite, make sure you import libicucore.dylib, i was getting the same error until i imported that library.

UISearchDisplayController and search performance with lots of data

I'm trying to figure out the best way to perform a fast search using a UISearchDisplayController.
I have a plist file with more than 36000 entries. I load this file in a dictionary and I perform the search in this dictionary. It works but it's kinda slow and there is lag between each touch event. I want an autocompletion effect so I need the search to be triggered for each touch event.
I tried using thread to perform the search in background with the following code :
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[NSThread detachNewThreadSelector:#selector(filter:) toTarget:self withObject:searchString];
return NO;
}
// Filter function looks like this
-(void) filter:(NSString *)search {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self.filteredList removeAllObjects]; // empty array of results
for (NSString *s in self.keys ) {
NSComparisonResult result = [s compare:search options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [search length])];
if (result == NSOrderedSame) {
[self. filteredList addObject:s ];
}
}
[ self.searchDisplayController.searchResultsTableView reloadData];
[pool release];
}
But my application crashes randomly with the following message:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (1) beyond bounds (0).
I'm sure it's because I dont use threading properly.
I also tried using [self performSelector:#selector(filter:) withObject:searchString afterDelay:0.5]; but I'm also facing application crashes.
What is the best way to handle this ? I'm not really good with threads but I think it's the best way to go, isn't it ? I also tried a solution with SQLite but the application is still not so responsive.
My data are actually zip codes and cities (36000 unique different cities but 6500 unique zip codes since multiple cities can have the same zip code). I want my search item to be either a zip code or a city name. I know that one big dictionary is definitely not the best structure. How could I organize my data for more efficiency?
Thank you for helping me with this.
The problem is that your search string is longer than one of your original strings in the array. When comparing from 0 to [search length] you are falling outside of s. You should first make sure that s is longer than search:
for (NSString *s in self.keys ) {
if ([s length]>=[search length]) {
NSComparisonResult result = [s compare:search options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [search length])];
if (result == NSOrderedSame) {
[self. filteredList addObject:s ];
}
}
}