Each guide I find on swift 2.0 error handling shows handling errors on a custom class. I know how to do, try, catch but what I don't know is what to catch. I know I'm testing for certain enum to indicate the error but where or how do i find these error enums if i did not create the class?
Im using
class func JSONObjectWithData(_ data: NSData,
options opt: NSJSONReadingOptions) throws -> AnyObject
so it says it throws and I would like to handle that but what does it throw? how do I know what enums to catch in the catch block? No doubt I'm missing something obvious but you know what it's like when you just can't spot it?
thanks
For methods in the Apple frameworks look into the documentation and compare the method signature with its Objective-C equivalent.
In this specific case the Objective-C equivalent is
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError * _Nullable *)error
so the object in the catch statement is an NSError object
do {
let jsonData = try JSONObjectWithData(someData, options:NSJSONReadingOptions())
} catch let error as NSError {
print(error)
}
And, if you guaranty it should returns object then you could use below code:
let jsonDataObject = try! JSONObjectWithData(someData, options:NSJSONReadingOptions())
Here, advantage is we can avoid to use "do { }" scope of syntax
Related
Suppose the following situation in Objective-C: an array of blocks.
So I want to run a block, I do:
myBlock block = blocks[0]();
Now imagine that this line runs inside a try:
myBlock block = blocks[0];
#try {
block();
} #catch {
// catch an error
}
Now imagine that I want add a line inside a block to force the catch.
What I did in objective-C was to add this line inside a block
[NSException raise:#"Failed" format:#"Failed", nil];
Now I want to do that in Swift
let myClousure = closures[0]
do {
myClosure!()
} catch {
}
The question is: what line should I add to a closure to force the same behavior, or in other words, to make the closure fail and the catch to be triggered?
Sorry if the question is stupid but I am new to Swift.
In Objective-C, you use #try/#catch blocks to handle ObjC exceptions such as the one you are raising. In Swift, you use do/catch blocks to catch Swift errors that are explicitly thrown from a "throwing" function. Only functions (and closures) marked with the "throws" keyword are allowed to throw an error, and if you call a function that can throw, you must handle the error.
If you have an array of closures, the type signature of the closure must specify that it can throw, e.g.
let blocks: [() throws -> Void] = // get some blocks
At this point, you can (and indeed must) handle any errors thrown by calling these blocks:
let block = blocks[0]
do {
try block()
} catch let error {
print(error)
}
I am porting some AppDelegate code for a plugin Objective-C to Swift.
My Objective-C is pretty good but I am stumped at understanding whats going on here. This is the code I am stuck on porting:
void (^safeHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result){
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(result);
});
};
I understand that the the ^ is for code blocks, but looking at this as a whole I am lost as to what is going on and how to port this to Swift.
I don't understand how there are two bracketed portions here:
void (^safeHandler)(UIBackgroundFetchResult)
If you can advise what that syntax is and how to port to Swift I would greatly appreciate it!
It's a block, which is a closure in Swift. This block is named safeHandler and takes a UIBackgroundFetchResult parameter and returns void.
This is the equivalent type:
let safeHandler: (UIBackgroundFetchResult) -> ()
And the whole thing would be
let safeHandler: (UIBackgroundFetchResult) -> () = { result in
dispatch_async(dispatch_get_main_queue()) {
completionHandler(result)
}
}
Note: block syntax is notoriously wonky. You can use this site to see the various block syntax forms: http://goshdarnblocksyntax.com/
I would like to do something like:
try {
SomeObjectiveClass.someMethod()
catch Error {
print("Recovered objc crash from Swift!")
}
I'm building an app where I type some visual constraints and I get the result or a message about any mistake.
Now, every time I type wrong constraints the app crashes, but I'd like to display a dialog with the error and let the user try again.
In my situation I don't have the "NSError-to-throws" automatic translation.
Consider this class:
#implementation SomeObjectiveClass
+ (BOOL)someClassMethodWithError:(NSError **)error {
// some something that
if (everythingOk) {
return true;
} else {
if (error) {
*error = [NSError errorWithDomain:kMyDomain code:kSomeErrorCode userInfo:#{NSLocalizedDescriptionKey : #"Some error message"}];
}
return false;
}
}
- (BOOL)someInstanceMethodWithError:(NSError **)error {
// some something that
if (everythingOk) {
return true;
} else {
if (error) {
*error = [NSError errorWithDomain:kMyDomain code:kSomeOtherErrorCode userInfo:#{NSLocalizedDescriptionKey : #"Some error message"}];
}
return false;
}
}
#end
You can then catch those errors like so:
do {
try SomeObjectiveClass.someClassMethod()
// or
let object = SomeObjectiveClass()
try object.someInstanceMethod()
} catch {
print("Recovered \(error) from Swift!")
}
Note, this catching of errors should not be confused with exception handling which we used to be able to do in Objective-C. Exceptions should be eliminated during the development process. The above is for legitimate runtime errors (e.g. failed network request or some other error that might occur due to conditions outside of the programmer's control).
To quote from Using Swift with Cocoa and Objective-C:
Although Swift error handling resembles exception handling in Objective-C, it is entirely separate functionality. If an Objective-C method throws an exception during runtime, Swift triggers a runtime error. There is no way to recover from Objective-C exceptions directly in Swift. Any exception handling behavior must be implemented in Objective-C code used by Swift.
I am having some issues migrating from Swift 1.2 to 2.0 particularly understanding error handling when calling methods from objective-c API. For example, I can't implement the method checkResourceIsReachableAndReturnError correctly. According to the Swift documentation for this method it will return a Bool. I want to check if a folder (self.baseURL) exists and tried the two following approaches:
let folderExists: Bool
do{
try folderExists = self.baseURL!.checkResourceIsReachableAndReturnError(){
} catch let error as NSError {
}
}
And:
let folderExists: Bool
var error: NSError?
do{
try folderExists = self.baseURL!.checkResourceIsReachableAndReturnError(&error){
} catch error as NSError {
}
}
But neither approaches work. I also thought that the Swift implementation of error throwing functions with the word AndReturnError would be shortened to checkResourceIsReachable but that does not seem to be the case.
I am sure I am doing something fundamentally wrong here and if someone has a suggestion for where to look I would appreciate that.
This method indeed returns a bool, it hasn't been modified to follow the new do try catch mechanism of Swift 2: it doesn't throw.
So you just use it like this, without do try catch:
var error:NSError?
let folderExists = self.baseURL!.checkResourceIsReachableAndReturnError(&error)
Excuses to my silly question, i wish to use a catch for specific exception, NSInvalidArgumentException, so, i have the next code in my OSX project:
#try
{
...
}
#catch(NSInvalidArgumentException* exception )
{
...
}
but xcode say me: "unknown type name 'NSInvalidArgumentException'", so i i was importing
import "Foundation/Foundation.h" or
import "Foundation/NSException.h"
but nothing happen, somebody known in what package or library is NSInvalidArgumentException? or which is my error? or is strictly necessary catch all exception using the superclass NSException? in the developer documentation do not show that so be it.
best regards.
NSInvalidArgumentException is not an exception type. It is a string that will be returned in the name property for an exception. So, you should catch your exception, and the name property does not match, you can re-#throw the exceptions you're not going to handle, e.g.:
#try {
// code that generates exception
}
#catch (NSException *exception) {
if ([exception.name isEqualToString:NSInvalidArgumentException])
{
// handle it
}
else
{
#throw;
}
}
See the Exception Programming Topics for more information.
I must confess that I share CodaFi's concern that this is not an appropriate use of exceptions. It's much better to program defensively, validate your parameters before you call Cocoa methods, and simply ensure that you don't generate exceptions in the first place. If you refer to the Dealing with Errors section of the Programming with Objective-C guide, exceptions are intended for "programmer errors" and they say:
You should not use a try-catch block in place of standard programming checks for Objective-C methods.
somebody known in what package or library is NSInvalidArgumentException?
It is declared in the Foundation Framework, in NSException.h. As CodaFi wrote in the comment, it is not a type, it is a string constant, declared as FOUNDATION_EXPORT NSString * const NSInvalidArgumentException;
So importing more headers won't fix your problem, because #catch(NSInvalidArgumentException* exception ) is like writing #catch(#"A string constant"* exception ), you have an object, where a type is expected.
Having said that, don't use exceptions for flow control. Have a look at the last part of this answer on SO