A reminder to myself around where and when to use NSError vs throwing exception in Objective-C.

This article gives a nice summary

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html

Use NSError for Most errors

When things go wrong in your app, due to

x network connectivity
x database been down etc

Use NSError and pass errors by reference.

- (BOOL)writeToURL:(NSURL *)aURL
 options:(NSDataWritingOptions)mask
 error:(NSError **)errorPtr;

Create an error pointer/reference and pass it to your method

NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL options:0
 error:&anyError];

if (!success) {
 NSLog(@"Write failed with error: %@", anyError);
 // present error to user
}

The recover if possible and display an error to the user.

Generating your own errors

To create your own error define your own error domain.

com.companyName.appOrFrameworkName.ErrorDomain

Along with a unique error code for each error that may occur.

NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
 NSString *desc = NSLocalizedString(@"Unable to…", @"");
 NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
 
 NSError *error = [NSError errorWithDomain:domain
 code:-101
 userInfo:userInfo];

Then use as follows

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr;

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr {
 ...
 // error occurred
 if (errorPtr) {
 *errorPtr = [NSError errorWithDomain:...
 code:...
 userInfo:...];
 }
 return NO;
}

Exceptions are Used for Programmer Errors

- (void)testInvalidUrl {
 XCTAssertThrows([self.player playURL:@"foobar" error:NULL], @"Invlaid url.");
}

- (BOOL)playURL:(NSString *)url error:(NSError **)errorPtr {
 if ([url containsString:@"track"]) {
 return [self.handler playTrack:url error:errorPtr];
 } else if ([url containsString:@"album"]) {
 return [self.handler playAlbum:url error:errorPtr];
 } else {
 [NSException raise:@"Invalid url" format:@"%@ must be a track or an album.", url];
 }
 return NO;
}