-
Notifications
You must be signed in to change notification settings - Fork 21
Description
The GeoPackage iOS library throws exceptions of type NSException
to signal that an operation could not be completed. This may occur, for instance, if a file system operation has failed.
Unlike Java or other programming languages, however, exceptions in Objective-C are not meant to stop execution due to an uncontrollable error at runtime, but are used to point out an unrecoverable mistake in the code:
When you’re writing code with Objective-C, exceptions are used solely for programmer errors, like out-of-bounds array access or invalid method arguments. These are the problems that you should find and fix during testing before you ship your app.
(Programming with Objective-C: Dealing with Errors)
The general pattern is that exceptions are reserved for programmer error only, and the program catching such an exception should quit soon afterwards.
(Exception Programming Topics: Exceptions and the Cocoa Frameworks)
Catching exceptions is not safe for use with automatic reference counting and may lead to memory leaks:
[ARC] does not end the lifetime of
__strong
variables when their scopes are abnormally terminated by an exception.It does not perform releases which would occur at the end of a full-expression if that full-expression throws an exception.
(LLVM: ARC, 7.7 Exceptions)
And there is no real way to catch NSExceptions in Swift:
In Swift, you can recover from errors passed using Cocoa’s error pattern, as described above in Catch Errors. However, there’s no safe way to recover from Objective-C exceptions in Swift. To handle Objective-C exceptions, write Objective-C code that catches exceptions before they reach any Swift code.
(Swift: Handling Cocoa Errors in Swift)
Instead, one should use Cocoa's error pattern:
Every program must deal with errors as they occur at runtime. The program, for example, might not be able to open a file, or perhaps it cannot parse an XML document. Often errors such as these require the program to inform the user about them. And perhaps the program can attempt to get around the problem causing the error.
Cocoa (and Cocoa Touch) offer developers programmatic tools for these tasks: the NSError class in Foundation and new methods and mechanisms in the Application Kit to support error handling in applications.
(Error Handling Programming Guide: Introduction to Error Handling Programming Guide for Cocoa)
For example, the method
- (BOOL)importGeoPackageFromPath:(NSString *)path
on GPKGGeoPackageManager
will throw an exception if a file could not be moved or copied or if a directory already exists. Instead, it should be converted to a method with the following signature
- (BOOL)importGeoPackageFromPath:(NSString *)path error:(NSError **)error
and set the error parameter in the case of those events. This would also allow it to be translated to a throwing void function in Swift. In Swift, it would have the signature
func importGeoPackage(fromPath path: String!) throws
allowing any errors to be caught. Similarly, the method
- (GPKGFeatureTable *)createFeatureTableWithMetadata:(GPKGFeatureTableMetadata *)metadata
on GPKGGeoPackage
should be converted to
- (GPKGFeatureTable *)createFeatureTableWithMetadata:(GPKGFeatureTableMetadata *)metadata error:(NSError **)error
allowing it to be translated to
func createFeatureTable(with metadata: GPKGFeatureTableMetadata!) throws -> GPKGFeatureTable
(For more information, see Swift: About Imported Cocoa Error Parameters.)
(EDIT: It would also be great if the library made use of nullability specifiers (Designating Nullability in Objective-C APIs).)
(This issue has been motivated by the two Stack Overflow posts Catching Both Objective-C and Swift Exceptions and Catching Both Objective-C and Swift Exceptions with Support for Return Values.)