Handling NSAsserts in Restkit throws - iphone

I am using Restkit's object manager to handle a good chunk of my remote API calls.
It throws NSAssert for a wide range of errors. For example, if the server returns a error page as opposed to well-formed JSON, it will raise an NSAssert, even if there is nothing wrong with the code.
There are a few things I am confused about (most of which has to do with general handling of exceptions and nsasserts).
How should we handle these NSAsserts errors? For example, we would want to retry again for a few times, then show a "something went wrong" message (as opposed to crashing the application).
I tried to use a catch-try block to catch the errors (code below), but the errors are not being caught. So my app just keeps failing. Furthermore, I am not comfortable using try-catch in release mode anyway.
Just for my understanding, why do Restkit use NSAsserts, as opposed to other failure?
Code:
// code to catch NSAssert that sharedManager throws
#try{
[sharedManager loadObjectsAtResourcePath:self.resourcePath delegate:self];
}
#catch (NSException *ex) {
NSLog(#"exception caught");
}

In general, you should NOT try to catch NSAssert errors, as they mean that something went horribly wrong - e.g. an application internal state become inconsistent, your are using library incorrectly etc., - and so application needs to quit.[1]
The reason your errors are not being caught is because NSAssert raises an NSInternalInconsistencyException[2], which is a string and not an instance of NSException. You can still catch them as per[3], e.g. with
#catch (id ex)
but it's not recommended for the reasons listed above.
To answer your 3rd question, please provide more details around which NSAssert is raised etc.
[1] What's the point of NSAssert, actually?
[2] http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/macro/NSAssert
[3] http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html

Related

How to handle error with Realm during writing?

I'm used to working with SQL database, I'm new to Realm and, so far, I'm really impressed by the ease of use of this new mobile database.
But there is something that I really don't undestand: how to handle error throwing?
Take this simple example:
I want to store in a Realm DB some market stocks.
Each stock has a "symbol" as a unique identifier: APPL for Apple Inc, TSLA for Tesla Motors Inc, etc.
I believe it would make sense to declare these symbols as primary keys, since it's not possible to have multiple times the same symbol in the database
When user clicks on a symbol (among a list of symbols), this symbol is saved in db.
In this Raywenderlich tutorial, it is said: "To simplify the code required in this tutorial, you’ll be used try! when calling Realm methods that throw an error. In your own code, you should really be using try and do / catch to catch errors and handle them appropriately."
So according to the following pattern:
do {
try realm.write {
realm.add(symbol)
}
}
catch let error as NSError {
print("Something went wrong: \(error.localizedDescription)")
}
So far it makes sense.
And if a user clicks on a symbol that is already in the database, I get (very logically) an error:
*** Terminating app due to uncaught exception 'RLMException', reason: 'Can't set primary key property 'symbol' to existing value 'APPL'.'
The problem is that this error is not catched during run time: I've got a crash instead.
My question is not about how to avoid such a crash, I understand of course that it's easy to avoid it by doing a simple testing before writing anything in the database :)
My question is how do we do in Realm to catch potential writing errors?
Am I doing something wrong?
do/try/catch in Swift catch Swift Errors, which are an entirely distinct thing from Objective-C exceptions. Realm follows Foundation's pattern for error reporting: API misuse errors throw exceptions which are not intended to be caught (and can't be caught in Swift), and recoverable errors throw Swift errors (or use NSError out parameters in Objective-C).
Adding an object with a duplicate primary key is considered API misuse, so it's a fatal error as the route for "handling" it is to fix the bug in your code. An example of a recoverable error which would produce a Swift error that would be caught by catch is running out of disk space while trying to save the new data.
There are two distinct types of error: programmer error, and expected errors. Realm handles these two types of errors differently.
Programmer error covers cases such as accessing objects from incorrect threads, out-of-bounds collection access, attempting to insert an object with a duplicate primary key, and so forth. Realm responds to these programmer errors by throwing an Objective-C exception. These exceptions are not intended to be caught and handled as they're indicative of a bug in a Realm user's code.
Expected errors cover things like files not existing, permission errors, failures to write to disk. These are things that can happen even with correctly-written code due to factors outside of the programs control. These are exposed as NSErrors and can be caught from Swift using do / try / catch. Note that Realm's Objective-C API has some convenience methods that don't expose the NSError. In these cases an expected error will throw an exception as there's no other avenue for Realm to communicate the failure. Rather than attempting to catch and handle exceptions raised by these convenience methods, you should use the variant of the API that returns an NSError instead.
Hi, the error line said "to existing value", don't you try to write more than one time the same primary key with 'APPL' ?
you need to update it, not override.
if you try to "add" again the same value, it's gonna stop you.
(sorry for bad english x) )

Exception handling in entire application

I have a few doubts regarding exception handling in iPhone. Here are they:
Suppose I have a chain of methods which are being called one after the other, that is, method A calls method B, which in turn calls method C, which calls method D. Which is the best place to put my try-catch block (is it method A or B or C or D or all of them). Also, I need to display an alert to user that an exception has occured and then, I want to log this exception to my server. So, if I am writing my try - catch block in all of this methods and if an exception occurs in method D; then I think the alert will be displayed 4 times and the web service for logging will also be called 4 times (till control reaches to catch block of method A). So, should I just use #throw; in catch block of method B, C and D and write my logic in catch block of method A (top level method) or should I avoid writing try - catch at all in methods B,C and D.
I need some sort of error code from the exception (because my web service needs parameters error-code and description). Is it possible to convert an exception to error or will I need to hard-code this code?
I had read somewhere about NSSetUncaughtExceptionHandler. And I think, if I can set this handler (in appDidFinishLaunching method of app delegate) and in the handler method, if I show to user some alert and call the web service; then I need not write try - catch block in each of my methods, in each of my classes. Am I right??
If an exception has occured and I have written either a try - catch block or NSSetUncaughtExceptionHandler, then will my app continue running or it will not respond to any of the user events. (I am sure it will handle the crash. What I want to know is whether it will hang)
Someone please enlighten me on this EXCEPTION TOPIC.
0) Avoid exceptions in Cocoa. They are generally non-recoverable. You might catch them for your own error reporting, but it's generally unsafe to assume you can recover from them.
1) If you need to catch, catch it immediately. Don't write your own throws -- instead, convert it to something like an NSError and pass that around. NSError can contain all the information you need to display or send an error code as well as a localized message.
2) You cannot convert an NSException into an NSError (directly) because an NSException does not have all the properties an NSError has - it is a different data representation. For one, an error code is not available. Two, the description is not localized. The best you can do is to create an error code and domain, then use the properties you need from the NSException and store that in an NSError. This could look something like the following:
// error checking omitted
extern NSString* const MONExceptionHandlerDomain;
extern const int MONNSExceptionEncounteredErrorCode;
NSError * NewNSErrorFromException(NSException * exc) {
NSMutableDictionary * info = [NSMutableDictionary dictionary];
[info setValue:exc.name forKey:#"MONExceptionName"];
[info setValue:exc.reason forKey:#"MONExceptionReason"];
[info setValue:exc.callStackReturnAddresses forKey:#"MONExceptionCallStackReturnAddresses"];
[info setValue:exc.callStackSymbols forKey:#"MONExceptionCallStackSymbols"];
[info setValue:exc.userInfo forKey:#"MONExceptionUserInfo"];
return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain code:MONNSExceptionEncounteredErrorCode userInfo:info];
}
#catch (NSException * exc) {
NSError * err = NewNSErrorFromException(exc);
...
}
If the APIs you use throw exceptions you are expected to catch and recover from (e.g. not truly exceptional cases), then yes, you could catch and attempt to continue. Unfortunately, anybody that writes exceptions in Cocoa with the intent that you will catch them probably does not understand the issues well enough to implement a solid unwind implementation (e.g. even if it produces leaks, it's not solid).
3) That's really not the time or place to display an alert. If you install a top level exception handler (via NSSetUncaughtExceptionHandler) - You should simply log a message -- then the exception handler will abort. Your app is in an unstable state -- continuing is worse than aborting. You may want to send these custom messages home, it's best to do so at the next launch of your app.
4) In the majority of cases, your app is in an unstable state and you should not continue. But, to actually answer it for those corner cases: "Yes, you can recover and continue when you catch, but you should only attempt to recover and continue when the throwing API states that recovery is supported. If the problem is beyond your control, and the problem is not exceptional (e.g. file not found), and the vendor really expects you to continue, then I would have to assume that they expect you to continue, even though it really isn't (100% safe).". Do not attempt to recover/continue from within your top level exception handler (the program will abort after it returns). If you want to be very fancy and present that immediately on OSX, another process would be best. If you are calling through a pure C++ interface, then the unwinding is well defined, and the need to catch is necessary - do continue if it is recoverable. Exceptions in C++ can be recoverable and well defined - they are also used quite extensively (including less than exceptional conditions).
(IMO...) Exceptions in ObjC should not have been introduced, and any method that throws from system or third party libraries should be deprecated. They don't unwind well, or in a well defined manner. As well, unwinding flows against normal Cocoa program flow. That means that touching any objc object's memory/relations that was in mutation at the time of the throw and which lies between the throw and the catch is as good as undefined behaviour. Problem is - you have no idea what that memory is (in most cases, and within reasonable maintenance time). C++ exceptions are well defined, and they unwind correctly (e.g. destructors are called) - but trying to continue in an ObjC context is ignoring any consequences of undefined behavior. IMO, they should only exist for ObjC++ (because C++ requires them).
In an ideal world, your ObjC programs and the libraries you use would not use exceptions (at all). Since you use libraries that do throw (including Cocoa), install a top level exception handler only if you need some special information about the error. Where the API mandates that you could expect an exception thrown due to circumstances beyond your control and you are expected to recover, then write a catch but immediately convert that logic to normal program flow (e.g. NSError) - you never need to write your own throw. -[NSArray objectAtIndex: and "object does not respond to selector" are examples of programmer errors - they should not be caught, but the program should be corrected.

Obj C: Creating a standard try-catch-block for use through the application

I am building a app with many different parts which access remote api calls (both my own, and others). There are many errors that might happen, and to exacerbate the problem, different libraries handle these errors differently.
Essentially, i would like to use the same error handling blocks for all these remote calls.
This is how i would do it with Ruby, but i am not that sure how to manipulate objective c in the same manner
//universal function to handle standard remote errors across errors
def universal_handling
begin
yield
rescue Exception => e
// handle different exceptions accordingly
// allow crash if unexpected exception
end
end
//how i would use the above block
universal_handling{ //any of my remote call here }
So, i have 2 questions (sample code very much appreciated)
How would I write the equivalent code in Objective-C? It is critical that I can use the same handling block throughout the app
In iOS dev, is this good practice?
Thanks for any help rendered! Error handling can be a major pain in the ass, so i do want to get this right early on =)
Notes:
Blocks are perfectly fine. I am not intending to support < 4.2 versions.
I read most of the articles out there, but none answers how you can use blocks to write "wrappers" for a specific set of calls.
You can do something very similar with blocks:
typedef void(^WrappableBlock)(void);
^(WrappableBlock block) {
#try {
block();
}
#catch(...)
}
//handle exception
}
}
However, it's very important to realize that the Cocoa (and CocoaTouch) libraries are not exception-safe. Throwing an exception through Cocoa frameworks will lead to all sorts of problems as the frameworks will not properly handle or clean up from the exceptions, leaving your application in a possibly inconsistent state. The correct Cocoa-style is to use NSError and return flags to indicate error conditions. This is neither better nor worse than using exceptions, just a different philosophy.
To do something similar to your universal_handling with NSError is not quite so straight forward because it will require that anything you call comply with the NSError pattern. That said:
typedef BOOL(^WrappableBlock)(NSError**);
^(WrappableBlock block, NSError **err) {
BOOL success = block(err);
if(!success) {
// handle error
}
return success;
}
would wrap any method that takes just an NSError** and returns a BOOL to indicate the presence of an error. Obviously the utility of this wrapper is limited as you'll have to wrap any interesting method in an other block to handle any other parameters. Of course, since it's the NSError** pattern, you can always just handle the errors when/where you want and pass NULL as the NSError** parameter where you don't care (ignoring the return value).
One final note: if you are using libraries that may throw exceptions, you must catch those exceptions within the scope of the library call and handle them. Do not let the exceptions propagate as they might then propagate through Cocoa framework code. Thus, the utility of the universal_handling block you propose is limited.
I would suggest you this nice cocoawithlove article that explains how to handle unhandled exceptions in Objective-C and also how to recover from an exception instead of "just" crashing. That could be a good alternative to what you are looking for.
I'm afraid that Objective-C not being as dynamic as ruby, that is a bit harder to do.
Would love to see a good block based implementation too, if that's possible, even If I'm not using them yet, because of previous version compatibility.

error handling vs exception handling in objective c

I am not able to understand the places where an error handling or where an exception handling should be used. I assume this, if it is an existing framework class there are delegate methods which will facilitate the programmer to send an error object reference and handle the error after that. Exception handling is for cases where an operation of a programmer using some framework classes throws an error and i cannot get an fix on the error object's reference.
Is this assumption valid ? or how should i understand them ?
You should use exceptions for errors that would never appear if the programmer would have checked the parameters to the method that throws the exception. E.g. divide by 0 or the well known "out of bounds"-exception you get from NSArrays.
NSErrors are for errors that the programmer could do nothing about. E.g. parsing a plist file. It would be a waste of resources if the program would check if the file is a valid plist before it tries to read its content. For the validity check the program must parse the whole file. And parsing a file to report that it is valid so you can parse it again would be a total waste. So the method returns a NSError (or just nil, which tells you that something went wrong) if the file can't be parsed.
The parsing for validity is the "programmer should have checked the parameters" part. It's not applicable for this type of errors, so you don't throw a exception.
In theory you could replace the out of bounds exception with a return nil. But this would lead to very bad programming.
Apple says:
Important: In many environments, use of exceptions is fairly commonplace. For example, you might throw an exception to signal that a routine could not execute normally—such as when a file is missing or data could not be parsed correctly. Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors. Instead you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object.
I think you are absolutely right with your assumption for Errors and for it framework provide a set of methods (UIWebView error handling ), But your assumption for Exception partially right because the exception only occurred if we do something wrong which is not allowed by the framework and can be fixed. (for example accessing a member from an array beyond its limit).
and will result in application crash.

Usage of NSException in iPhone Apps

One of my friends asked me not to use NSException in iPhone Apps. The reason he gave was "performance bottleneck". But I am not convinced of it.
Can someone confirm me that we should restrain from using NSException in iPhone App? If you have best practices for using NSException, please provide that too.
UPDATE:
This link requests us to use Exception handling at the app level. Have someone ever done it? Please give the advantages of it and any other performance hitches it could create.
In short:
Do not use exceptions to indicate anything but unrecoverable errors
It is only appropriate to use #try/#catch to deal with unrecoverable errors. It is never appropriate to use #throw/#try/#catch to do control-flow like operations on iOS or Mac OS X. Even then, consider carefully whether you are better off using an exception to indicate an unrecoverable error or simply crashing (call abort()); a crash often leaves behind significantly more evidence.
For example, it would not be appropriate to use for catching out-of-bounds exceptions unless your goal is to catch them and somehow report the error, then -- typically -- crash or, at the least, warn the user that your app is in an inconsistent state and may lose data.
Behavior of any exception thrown through system framework code is undefined.
Can you explain the "Behavior of any
exception thrown through system
framework code is undefined." in
detail?
Sure.
The system frameworks use a design where any exception is considered to be a fatal, non-recoverable, error; a programmer error, for all intents and purposes. There are a very limited number of exceptions (heh) to this rule.
Thus, in their implementation, the system frameworks will not ensure that everything is necessarily properly cleaned up if an exception is tossed that passes through system framework code. Sine the exception is, by definition, unrecoverable, why pay the cost of cleanup?
Consider this call stack:
your-code-1()
system-code()
your-code-2()
I.e. code where your code calls into system code which calls into more of your code (a very common pattern, though the call stacks are obviously significantly deeper).
If your-code-2 throws an exception, that the exceptions passes over system-code means the behavior is undefined; system-code may or may not leave your application in an undefined, potentially crashy or data-lossy, state.
Or, more strongly: You can't throw an exception in your-code-2 with the expectation that you can catch and handle it in your-code-1.
I've used exception handling for my fairly intensive audio app with no problems whatsoever. After much reading and a bit of benchmarking and disassembly analysis, I've came to the controversial conclusion that there is no real reason not to use them (intelligently) and plenty of reason not to (NSError pointer-pointers, endless conditionals...yuck!). Most of what people are saying on the forums is just repeating the Apple Docs.
I go into quite a bit of detail in this blog post but I'll outline my findings here:
Myth 1: #try/#catch/#finally is too expensive (in terms of CPU)
On my iPhone 4, throwing and catching 1 million exceptions takes about 8.5 seconds. This equates to about only 8.5 microseconds for each. Expensive in your realtime CoreAudio thread? Maybe a bit (but you'd never throw exceptions there would you??), but an 8.5μs delay in the UIAlert telling the user there was a problem opening their file, is it going to be noticed?
Myth 2: #try Blocks Have a Cost On 32bit iOS
The Apple docs speak of "zero-cost #try blocks on 64bit" and state that 32 bit incurs a cost. A little benchmarking and disassembly analysis seems to indicate that there is zero-cost #try blocks on 32bit iOS (ARM processor) as well. Did Apple mean to say 32bit Intel?
Myth 3: It Matters that Exceptions Thrown Through Cocoa Frameworks are Undefined
Yes, they are "undefined", but what are you doing throwing through the Apple framework anyway? Of course Apple doesn't handle them for you. The whole point of implementing exception handling for recoverable errors is to handle them locally - just not every-single-line "locally".
One edge case here is with methods like NSObject:performSelectorOnMainThread:waitUntilDone:. If the later parameter is YES, this acts like a synchronous function in which case you might be forgiven for expecting the exception to bubble up to your calling scope. For example:
/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCThread
/////////////////////////////////////////////////////////////////////////
#interface l5CCThread : NSThread #end
#implementation l5CCThread
- (void)main
{
#try {
[self performSelectorOnMainThread:#selector(_throwsAnException) withObject:nil waitUntilDone:YES];
} #catch (NSException *e) {
NSLog(#"Exception caught!");
}
}
- (void)_throwsAnException { #throw [NSException exceptionWithName:#"Exception" reason:#"" userInfo:nil]; }
#end
/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCAppDelegate
/////////////////////////////////////////////////////////////////////////
#implementation l5CCAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
l5CCThread *thd = [[l5CCThread alloc] init];
[thd start];
return YES;
}
// ...
In this case the exception would pass "through the cocoa framework" (the main thread's run loop) missing your catch and crashing. You can easily work around this using GCD's dispatch_synch and putting in it's block argument the method call plus any exception handling.
Why Use NSException's over NSError's
Anyone who's ever done work in one of the older C-based frameworks like Core Audio knows what a chore it is checking, handling and reporting errors. The main benefit #try/#catch and NSExceptions provides is to make your code cleaner and easier to maintain.
Say you have 5 lines of code which work on a file. Each might throw one of, say, 3 different errors (eg out of disk space, read error, etc.). Instead of wrapping each line in a conditional which checks for a NO return value and then outsources the NSError pointer investigation to another ObjC method (or worse, uses a #define macro!), you wrap all 5 lines in a single #try and handle each error right there. Think of the lines you'll save!
By creating NSException subclasses, you can also easily centralise error messages, and avoid having your code littered with them. You can also easily distinguish your app's "non-fatal" exceptions from fatal programmer errors (like NSAssert). You can also avoid the need for the "name" constant (the subclass's name, is the "name").
Examples of all this and more details about the benchmarks and disassembly are on this blog post...
Exceptions plus try/catch/finally is the paradigm used by pretty much every other major language (C++, Java, PHP, Ruby, Python). Maybe its time to drop the paranoia and embrace it as well...at least in iOS.
Generally ask yourself if you're trying to signal an error, or do you actually have an exceptional condition? If the former, then it's a very bad idea regardless of any performance issue, real or perceived. If the latter, it's most definitely the right thing to do.