Hey, I'm using a ScriptDebugDelegate to notify me when an exception occurs in the exceptionWasRaised function.
However, I'd like to know how I could ignore the exception, ie. just skip the line of code that'd normally fire an exception.
Thanks
ASH
If you know the line where the exception occurs you could use a try/catch with no code inside the catch block
#try {
//my code that throws exception
} #catch ( NSException *e ) {
}
You can even filter it by using a specific exception type that you want like for CustomException:
#try {
//my code that throws exception
} #catch ( MyCustomException *e ) {
}
What will cause any MyCustomException to be ignored, and all other to be fired.
NOTE: It is important to use that only for testing and debugging proposes as empty catches are always wrong.
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 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 have a problem with the following code example:
Windows::Storage::StorageFolder^ location = Package::Current->InstalledLocation;
try
{
task<StorageFile^> GetFileTask(location->GetFileAsync(sn));
GetFileTask.then([=](StorageFile^ file)
{
try
{
task<IBuffer^> ReadFileTask(FileIO::ReadBufferAsync(file));
ReadFileTask.then([=](IBuffer^ readBuffer)
{
// process file contents here
});
}
catch(Platform::Exception^ ex)
{
// Handle error here
}
});
}
catch(Platform::Exception^ ex)
{
// Handle error here
}
When using a filename that doesn't exist the function throws an exception:
Unhandled exception at 0x0FFCC531 (msvcr110d.dll) in GameTest2.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.
I've been searching the internet and this exception breaks only when connected to the debugger. I'm using VS 2012. I've turned off all the relevant 'break on exception' but it still causes the debugger to break and non of my handlers are getting a chance to handle the exception.
If the file is missing I would expect the GetFileAsync method to throw a 'File doesn't exist' exception. Not sure why it keeps throwing the 'Invalid parameter' exception.
This is starting to bother me and I just can't find any known solution to this issue. Anyone have any ideas?
I'm going to try and change the method to not use the task<> code. Instead I'll call the GetFileAsync using 'await'. However I believe 'await' will just cause the calling thread to wait until the GetFileAsync has finished, which kind of defeats the point of asynchronous loading.
I'm wondering if this is a common issue with exception handling when using tasks.
Update:
OK, I've now found the solution:
task<StorageFile^>( location->GetFileAsync(sn)).then([](StorageFile^ openedFile)
{
return FileIO::ReadBufferAsync(openedFile);
}).then([](IBuffer^ readBuffer)
{
// Process file
}).then([](task<void> t)
{
try
{
t.get();
}
catch(Platform::Exception^ e)
{
// Handle error
}
});
It seems there needs to be an extra 'then' condition added to the end of the chain to pick up the exception.
I have a unit test that tests if method throws an exception when condition is present, and method does throws exception as expected.
- (void)testMethodThrowsWhenConditionIsPresent {
XCTAssertThrows([Foo methodWithCondition: condition], #"Condition is true, method should throw exception");
}
Here is the exception source:
- (void)methodWithCondition:(someType)condition {
if (condition) {
[NSException raise: #"condition is true!" format: #"condition is true!"];
}
}
Why does the test stop at the line the exception is thrown? The test does not go on, it stops at that line, when I expect it to continue and return 1 from XCTAssertThrows(), making the test succeed. The test instead stops with Xcode bringing me to the line it was thrown, with a green `Thread 1: breakpoint 1.1' and the debugger appearing in the console.
Why does the test stop when the execution is thrown?
Because you have a breakpoint, which stops execution.
Why, after removing the breakpoint, does my application crash when the exception is thrown?
Because you have an unhandled exception. Unhandled exceptions cause your program to crash.
How can I handle an exception so it won't crash my program?
The easy answer to this question is to simply NOT throw an exception. In other programming languages, like Java, this is perfectly standard. But in Objective-C, we don't really do exceptions. In Objective-C, exceptions should be saved for TRULY exceptional behavior.
With that said, and a strong suggestion for you to find another way to handle whatever it is you're trying to handle, this is how you handle an exception in Objective-C:
#try {
// code that could throw an exception
}
#catch (NSException *e) {
// handle the exception...
}
#finally {
// post try-catch code, executed every time
}
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