Domanda

I’ve seen Objective C code using a collection of practices, raging from passing a pointer of NSError for execution finish status - to using ‎NSAssert - to implementing @throw - to relaying on delegate for status code returned in the callback - to the old c method of returning a boolean/int indicating with 1 being success and co.

I can’t identify a consistent pattern for how should I be handling errors happening in my app running on client devices. For ex, what would you recommend handling for the following cases:

  • Client attempt to access a network resource, network resource timed out / returned 500?
  • Unexpected state that should have not even happened reached in logical code section?
  • Attempt to write to disk failed? (Out of disk space, not permission and code)

Coming from Java, server side practices exceptions the weapon of choice, using Objective C and C is seems that exceptions exist but are not encouraged. NSAssert seems harsh, as it will crash the application, which in most cases is not the optimal solution. So, I’d appreciate a Best practices advice.

È stato utile?

Soluzione

Exceptions are used to indicate programmer error and/or non-recoverable errors only. Exceptions should not be used for flow control. NSAssert is more of a development tool. Use NSError for recoverable, user addressable (or caused) errors.

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/ErrorHandling/ErrorHandling.html

Altri suggerimenti

First we have to agree upon the terminology. I think there are two types of bad situations in a program: Errors and Exceptions.


Errors An unwanted situation that can happen but you can recover from it with the program memory being in a consistent state and further execution can continue.

eg1. Client attempt to access a network resource, network resource timed out / returned 500? eg2. Attempt to write to disk failed? (Out of disk space, not permission and code)

Approach Handle the error the way you want it handled. Show user message, log it to file/console, report it to your back-end if you think it needs to be reported.


Exceptions A state that should never have been reached and may corrupt the memory state of the app in a way that prevents further execution.

This could happen at two levels.

Level 1 A logic error that you have overlooked and is now causing the exception.

eg1. accessing invalid array elements i.e. index out of bound exception.

In the above example, you unconsciously made a programming mistake. You couldn't have handled it because you overlooked it. This will crash the application.

Approach Your approach here should be to identify the bug and fix it. In the process some end users will be affected which is the case with the most meticulous software.

Level 2

As you are programming, you come across a situation that your business logic doesn’t permit.

eg1. Unexpected state that should have not even happened reached in logical code section?

eg2. A database entry that you always expect to be present as per your business logic. For example, let's say you are making an app that requires a currency table with currency names, unicode symbols for currencies and country names. The value from this table are to be shown as a drop down in your UI. You may create a table upon first launch of the app and insert the values or may be you ship the table in the bundle but you always expect it to have the values you are inserting. You make an sqlite select query->sqlite execution succeeds->but no values are returned. Business logic demands that values should be present but for some mysterious reason they are absent.

Here is where most confusion stems from because sometimes you can recover from some of these situations by treating them as errors and displaying a message to the end user. This approach is wrong. This is an exception at business logic level. One that you should prevent from happening.

Approach You should force crash the app here as well using NSAsserts both in development and production mode. This is an aggressive approach and some end users will be affected, but I have read experts advising to adopt an aggressive approach to finding bugs and remedying them rather than pretending they don’t exist or thinking you have smartly covered them all when all you have done is masking exceptions as errors through your “handling tactics”. I believe the experts are right. Coming from Java, you may find it a very objCeee.. way of doing things.


Nils and Bools You should understand that they are just facilitators to reach at the conclusion of whether you treat something as an error or exception. They are not the end in themselves. While writing your methods with return value, you should define what a nil or bool(no) signifies and document your intent on top of the method. Sometimes it would be an error, sometimes it would be an exception, sometimes it could be a normal expected result. While dealing with apple frameworks/third party libraries you should understand what their intent is when they return such values and determine how you want to treat them in your code.


Some other tips

  1. Don’t use @try/catch because experts say so. If you wish to challenge them assuming that Apple has put it there for a reason, Apple is always right, experts(including Apple employees themselves) have got it wrong after all these years, you can go ahead and do it.

  2. Formalize your approach to this->stick to it->document your intent. Don’t think it over and over. Because at some stage error/exceptions/nils/bools would cross the limits of propriety and reach the precincts of taste. You will be better off settling this once and for all and freeing up your time.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top