Catch an objectiveC exception that was thrown as a result of a javascript script - ios

Is there any way of catching an Objective-C exception that was thrown as a result of a JavaScript script evaluation?
For example:
I have a class Obj with a method canThrow that I have exported through JSExport. From some script I call this method and it indeed throws an exception.
Any way I can handle it?
I have already tried to wrap the script evaluation code in a try-catch, but that didn't help.

Your question is a little bit unclear, but I will try to answer it anyway.
If you need to raise an exception from Objective-C to Javascript, you should use -[JSContext exception] property. See following question for details.
Passing exception from Javascript to Objective-C is straightforward, you simply export some method, that will handle exception in Objective-C like:
myJSContext[#"PassExceptionToObjC"] = ^void(JSValue *)jsException {
// Handle exception
}
And then use following code in Javascript:
try {
// some code
}
catch (exception) {
PassExceptionToObjC(exception);
}
Alternatively you can return specific value from your Javascript to Objective-C. Like:
function doSomething() {
try {
// Do something
return 'Ok';
}
catch (error) {
return 'Error happens ' + error.message;
}
}
In case you need to avoid throwing Objective-C exception in method, called from Javascript, you simply should add #try/#catch in your Objective-C method or block:
myJSContext[#"DoSomething"] = ^void(JSValue *)someValue {
#try {
// Do something
}
#catch (NSException *exception) {
// Handle exception
}
}
Or, preferred, change logic of Objective-C code, that trigger exception.
Similar way applies if you need to avoid exception in Javascript, called from Objective-C. You simply add try/catch. In most cases you may simply ignore exceptions in JavaScript, called from Objective-C. But I suggest to implement exception handing on Objective-C side for any non-trivial Javascript, at least to simplify troubleshooting.
Hope it helps.

Related

Catching vs. not catching specific error types in dart - any difference in behavior?

My understanding of catching errors was that if a certain error is 'caught', the code in a method following the catch block would not execute unless you have a finally statement afterwards.
However, if I catch a certain error type, but don't have a return or a throw/rethrow statement at the end, it does seem to keep going with the further code in the method.
I am catching a certain exception type, with the statement on CustomException catch (error) but I'm not planning to rethrow the error, and I don't need to do anything with the actual error. I don't have a return or a rethrow statement, as I assumed the catch block. I have two questions to make sure I'm understanding this behavior properly:
First question - if I don't plan to use the specific error inside my catch block, does adding catch (error) after on CustomException actually make a difference? It seems like it's ok to do it with or without it.
Second question - does my catch block need to have a return/throw/rethrow statement at the end in all cases to prevent the method from performing any further code?
Code example 1: With the catch (error) statement:
try {
...
} on CustomException catch (error) {
...
} catch (error) {
rethrow;
}
print('Is this method still running?');
Code example 2: without the catch (error) statement:
try {
...
} on CustomException {
...
} catch (error) {
rethrow;
}
print('Is this method still running?');
Your two examples aren't the same; one catches CustomException and the other catches PlatformException. Presuming that you meant them to be the same, then the difference between on CustomException and on CustomException catch (error) is that the second way allows you to do something with the thrown object (or if you use on CustomException catch (error, stacktrace), to do something with the stacktrace too).
The Dart Language Tour covers this:
Use on when you need to specify the exception type. Use catch when your exception handler needs the exception object.
Additionally, doing:
catch (error) {
rethrow;
}
is unnecessary noise. Just omit it and let the thrown exception go uncaught.

Call objc code that throws exception in Swift

I have this code in ObjC/C:
AVCaptureFocusMode GetFocusModeWithString(NSString *mode) {
if ([mode isEqualToString:#"locked"]) {
return AVCaptureFocusModeLocked;
} else if ([mode isEqualToString:#"auto"]) {
return AVCaptureFocusModeAutoFocus;
} else {
#throw [NSError errorWithDomain: #"FocusError", code: 12];
}
}
It used to be working fine when calling from ObjC code. Now I am rewriting the caller side using swift. However, in swift, this code does not actually throw:
// does not work, swift thinks this function does not throw.
do {
try GetFocusModeWithString(#"auto")
}
Am I doing anything wrong here? Is the ObjC code bad? how can I improve the ObjC code to work nicely with swift?
Objective C does not have do/try/catch semantics the way that Swift does.
#throw causes a runtime exception. This isn't something you can catch in Swift.
The way that you can integrate Cocoa error handling with Swift is described in the Swift Objective C interoperability documentation and this answer
First declare your Objective-C function to accept a pointer to an instance of NSError. Then you can flag that parameter with function with __attribute__((swift_error(nonnull_error))).
This will cause a Swift exception if the error is non-null when the function returns
- (AVCaptureFocusMode) getFocusModeWithString:(NSString *) mode error: (NSError **)error __attribute__((swift_error(nonnull_error))); {
*error = nil;
if ([mode isEqualToString:#"locked"]) {
return AVCaptureFocusModeLocked;
} else if ([mode isEqualToString:#"auto"]) {
return AVCaptureFocusModeAutoFocus;
}
*error = [NSError errorWithDomain:#"FocusError" code:12 userInfo:nil];
return -1;
}
Now, in your Swift code you can call it with
do {
let focusMode = try getFocusMode(with: "auto")
} catch {
print(error)
}
Note that this will change your method signature in Objective-C; You will need to pass &error to the method and check its value on return.
Objective-C exceptions are not compatible with Swift. Here's what Apple says:
Handle Exceptions in Objective-C Only
In Objective-C, exceptions are distinct from errors. Objective-C exception handling uses the #try, #catch, and #throw syntax to indicate unrecoverable programmer errors. This is distinct from the Cocoa pattern—described above—that uses a trailing NSError parameter to indicate recoverable errors that you plan for during development.
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.

Why does this function return finaly?

Why does this function return finaly? Is not we catching the error?
String _test(){
try {
throw Exception('error');
} catch (e) {
return 'catch';
} finally {
return 'finaly';
}
}
Finally block is executed regardless of catching the error. It always executes when the try block exits.
EDIT:
https://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break.
From this quote, it is evident that finally is usually used for cleaning up the code. That's why it is executed before the catch block, to avoid being bypassed by return

what is alternative of for in in darjs?

I am looking for the alternative of javascript for in in dart:js?
for example:
if('addEventListener' in event) {
event.addEventListener(change);
}
I used is operator, but it's throwing an error in Safari becouse addEventListener does not exist in event.
if(event.addEventListener is Function) {
event.addEventListener(change);
}
Checking whether an object supports a specific method is not something you do in Dart. You should check that the object implements an interface which has that method.
In this example, you probably need:
if (event is EventTarget) {
event.addEventListener("change", change);
}
If you think that the object might support the function, but you don't actually know which interface it gets the function from, then you can do what you try here, using a dynamic lookup, but you need to catch the error you get if the function isn't there.
dynamic e = event; // if it isn't dynamic already.
Object addEventListener;
try {
addEventListener = e.addEventListener;
} on Error {
// ignore.
}
if (addEventListener is Function) {
addEventListener(...);
}

When to use Future.handleexception in Dart and when to try-catch

I'm trying to really get Futures in Dart and I've noticed that just about every example I come across uses handleException to deal with exceptions that complete the Future. Yet the API documentation states "In most cases it should not be necessary to call handleException, because the exception associated with this Future will propagate naturally if the future's value is being consumed. Only call handleException if you need to do some special local exception handling related to this particular Future's value."
So when would I need "special local exception handling"? Could someone explain that in a bit more detail? Is there some code that I honestly can't run easily by letting the exception propagate?
Mads Ager gave me this answer:
Basically, this is the equivalent of having a try-catch in straight-line code:
int doSomethingElse() {
try {
return thisMightFail();
} catch(e) {
return -1;
}
}
void doSomething() {
int value = doSomethingElse();
// operate on value
}
With Futures it is something like this (not tested):
Future<int> doSomethingElse() {
return thisMightFail().transformException((e) => -1);
}
void doSomething() {
doSomethingElse().then((value) {
// operate on value
});
}
So this is for local exception handling instead of global exception handling. If you never use handleException or transformException that would correspond to always dealing with exceptions at the top level in non-async code.

Resources