How to enable exception handling in objective-c and xcode - iphone

EDIT: Issue has been solved(partially):It is a simulator bug. I've compiled and tested this on two devices with iOS 3.1.3 and 4.0. The exception was handled correctly. Be careful, the simulator is your enemy!
this is driving me crazy. I don't know how to enable exception handling in my project. Look at the code and debugger output below.
My Goal is to catch the exception, not correcting the code so the exception is handled and the app doesn't crash.
I'm using XCode 3.2.3, iPhone SDK 4 final. I have just created a simple view based iPhone App to test this.
I have looked in my project settings and yes the switch "Enable Objective-C Exceptions" is checked. I am using GCC 4.2.
When I look at the build process in detail the compiler flag -fno-objc-exceptions is not within the list of arguments!
What am I missing here?
Thanks in advance
Nick
NSArray * foo = [[NSArray alloc] init];
#try {
NSLog(#"trying...");
[foo objectForKey:#"yeah"];
}
#catch (NSException * e) {
NSLog(#"catching %# reason %#", [e name], [e reason]);
}
#finally {
NSLog(#"finally");
}
leads to
trying...
-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780'
*** Call stack at first throw:
(
0 CoreFoundation 0x02393919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x024e15de objc_exception_throw + 47
2 CoreFoundation 0x0239542b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x02305116 ___forwarding___ + 966
4 CoreFoundation 0x02304cd2 _CF_forwarding_prep_0 + 50
...
)
terminate called after throwing an instance of 'NSException'
Whether the catch nor the finally block is ever reached.

Quote from How do I catch global exceptions? :
"objc_exception_throw is not an exception. It is the function that throws Objective-C exceptions. Similarly, EXC_ARITHMETIC is not an Objective-C exception; it is a Mach (kernel) exception, meaning that your app tried to do something completely invalid. – Peter Hosey May 14 at 9:14"
That thread does have a link to a solution for your problem though, it appears. The link goes to http://www.restoroot.com/Blog/2008/10/20/crash-reporter-for-iphone-applications-part-2/ which looks a little risky, but if it works, it might be worth it for you.
There are bug reports related to this, e.g.: http://www.openradar.me/8081169 (posted earlier this month)
(Updated to summarize information from comments below.)

If I understand your problem right.
Your Try/ catch block is working correctly.
It is trying to run your code, and catches an error.
You need to decide what to do when it catches an error and code for it within the block.
I normally do that in the CATCH part. As the finally bit will execute regardless of an exception or not being thrown.

Your example code is catching the NSException exception but not the one being thrown, NSInvalidArgumentException. You might have better luck if you look for that specific exception.
NSArray * foo = [[NSArray alloc] init];
#try {
NSLog(#"trying...");
[foo objectForKey:#"yeah"];
}
#catch (NSInvalidArgumentException *e) {
NSLog(#"Invalid argument called.");
}
#catch (NSException * e) {
NSLog(#"catching %# reason %#", [e name], [e reason]);
}
#finally {
NSLog(#"finally");
}
I don't have any way of testing it myself right now, though.
See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocExceptionHandling.html for more information.

Related

SoundCloud iOS starting Tutorial - unrecognized selector

I am following the iOS quick start tutorial and I have gotten as far as creating the button to login to SoundCloud but I'm getting this error:
2013-05-01 15:00:44.698 SoundCloudSample[60999:c07] +[SCSoundCloud shared]: unrecognized selector sent to class 0x3a568
2013-05-01 15:00:44.701 SoundCloudSample[60999:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[SCSoundCloud shared]: unrecognized selector sent to class 0x3a568'
* First throw call stack:
(0x192a012 0x174fe7e 0x19b52ad 0x1919bbc 0x191994e 0x2ad0 0x17507cf 0x1757a0d 0x174eaeb 0x174ee22 0x17610e1 0x1763705 0x8c02c0 0x8c0258 0x981021 0x98157f 0x9806e8 0x8efcef 0x8eff02 0x8cdd4a 0x8bf698 0x1da7df9 0x1da7ad0 0x189fbf5 0x189f962 0x18d0bb6 0x18cff44 0x18cfe1b 0x1da67e3 0x1da6668 0x8bcffc 0x1f0d 0x1e35)
libc++abi.dylib: terminate called throwing an exception
(lldb)
- (IBAction) login:(id)sender {
SCLoginViewControllerCompletionHandler handler = ^(NSError *error) {
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Error: %# ", [error localizedDescription]);
} else {
NSLog(#"Done");
}
};
[SCSoundCloud requestAccessWithPreparedAuthorizationURLHandler:^(NSURL *preparedURL){
SCLoginViewController *loginViewController;
loginViewController = [SCLoginViewController loginViewControllerWithPreparedURL:preparedURL completionHandler:handler];
[self presentModalViewController:loginViewController animated:YES];
}];
}
I'm not sure exactly what I'm doing wrong since I followed the tutorial.
I'm also confused about the client_id, secret, and redirect URI.
Here is the code for that:
- (void) initialize {
[SCSoundCloud setClientID:#"98e77c3e4da0cc49f2f8e58f278bb813" secret:#"b8311d06a82a8c824b64b8a719479cda" redirectURL:[NSURL URLWithString:#"http://soundcloud.com/connect?client_id=98e77c3e4da0cc49f2f8e58f278bb813&redirect_uri=evesdropmusic://oauth"]];
}
Maybe I overlooked something...
I have found the solution to the problem!
Apparently I think I found a bug in the newest version of XCode.
on the "Other Linker Flags" under the Targets section -- Build Settings, I found that even though I entered the "-ObjC, -all_load", XCode decided not to save those credentials.
The fix is to enter the flags with the (+) - click on them again, then if they go away, enter it again. It should save this time. Sometimes this doesn't occur. I'm not sure why my entries do not remain.
Once I added these again, this fixed the issue.

GameCenter function crashes app - can anyone help to solve?

I have a crash log for my current iPhone app which is symbolicated, but I am having trouble deciphering what the problem is still.
The basic issue is that on certain devices (particularly older ones) my app with crash back to the home screen. It appears to be when a user comes back to my game after a while - which initiates a login process to the Game Center. I have pasted the relevant part of the crash log below:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x2e000000
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x37c11f7e objc_msgSend + 22
1 Transfer Quiz 0x000023c4 -[GameCenterManager callDelegate:withArg:error:] (GameCenterManager.m:113)
2 Transfer Quiz 0x0000230c __60-[GameCenterManager callDelegateOnMainThread:withArg:error:]_block_invoke_0 (GameCenterManager.m:103)
3 libdispatch.dylib 0x346fdc52 _dispatch_call_block_and_release + 6
4 libdispatch.dylib 0x346ffee0 _dispatch_main_queue_callback_4CF$VARIANT$mp + 188
5 CoreFoundation 0x358432a6 __CFRunLoopRun + 1262
6 CoreFoundation 0x357c649e CFRunLoopRunSpecific + 294
7 CoreFoundation 0x357c6366 CFRunLoopRunInMode + 98
8 GraphicsServices 0x37462432 GSEventRunModal + 130
9 UIKit 0x332d2cce UIApplicationMain + 1074
10 Transfer Quiz 0x000030d4 main (main.m:16)
11 Transfer Quiz 0x000021a8 start + 32
and here is the following code for GameCenterManager callDelegate:
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(#"Missed Method");
}
}
The code was part of a tutorial on an external tutorial website - and I cannot pinpoint the issue that's causing my app to crash here.
Does anyone know of a reason why code is causing the crash? Any help would be much appreciated. I am finding it very hard to replicate the crash on any device and using NSZombies is also not working probably due to my inability to recreate the crash.
Thank you all, in advance.
It seems that the selector you're calling takes 2 arguments: an 'arg' and an 'error'. Now the thing is that if 'arg' is nil, you're calling the selector to one argument only - so the second argument is basically garbage, and when the object on which the selector is called tries to access the second argument, it crashes. All in all, you don't need that if() - always pass both arguments to the selector and let the delegate detect if its first argument is nil.

try and catch is not handling exception in iphone

i am using the following code to catch an error when ind.row is not a valid value or sometimes it becomes nil
#try {
if(ind.row<[[treeNode flattenElements] count])
{
[self.mTableView scrollToRowAtIndexPath:ind atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
#catch (NSException *e) {
NSLog(#"%#",e);
}
but when this code executes sometimes this error is occuring
Assertion failure in -[NSIndexPath row], /SourceCache/UIKit_Sim/UIKit-1262.60.3/UITableViewSupport.m:1948`
what may be the reason for this error and why exception is not being handled
Assertions in iOS don't throw exceptions, so you can't catch them.
You are going to need to figure out what's wrong with your call to -row. My first guess would be that "ind" is already freed or something.
You'll have to check the index, generate and raise an exception on you own:NSException Class Reference
+ (void)raise:(NSString *)name format:(NSString *)format, ...
actually it was already catching the exceptions...i had set the flag stop on objc exceptions.when i removed that it catching the exceptions.... as pointed out by #stilesCrisis the ind value was null at the time of this exception..sorry for the trble

iphone - try, catch question

I have a method that has several parts that can throw an exception. If one of these parts fail, I would like the cleaning method to run. I am thinking about using the try/catch directive.
My question is: will I have to use one directive for every line of code that can throw an exception or can I simply include the whole method in a block like this?
#try {
[self doStuff];
// doStuff has several passages that could throw an exception
}
#catch (NSException * e) {
[self cleanTheWholeThing];
}
In this case it is not important to me which line generated the problem. I just need the method to run successfully or do other stuff in case it fails.
thanks
If you can, avoid exceptions. Even Apple recommends to avoid them:
Instead of exceptions, error objects (NSError) and the Cocoa error-delivery mechanism are the recommended way to communicate expected errors in Cocoa applications.
See also their Error Handling Programming Guide (it's marked as being Mac related but is equally valid for iPhone, the same concepts apply).
The reasons for avoiding exceptions are that I know of are:
They are slower than reporting via NSError and an out-pointer.
They can result in memory leaks if you aren't very careful. Some memory leaks due to exceptions cannot be avoided at all (in non-GC environments).
You might forget to catch them, and then your app crashes.
In general, exceptions in Objective-C are used for really exceptional problems that are often unrecoverable. They are almost never used in area where you expect something can go wrong (like network communication; the NSURLConnection methods do not throw exceptions for this reason but export an NSError). This may be different from other languages where exceptions are used more often. In the projects I've been working on I had only once the need to catch and handle an exception (can't remember which, though).
Instead, you should do something like this:
// Returns YES when successful.
- (BOOL)doSomething:(NSError **)outError
{
// ...
if (someErrorOccurred) {
if (outError) {
outError = [NSError
errorWithDomain:#"MyErrorDomain"
code:123
userInfo:nil
];
// Or maybe even use your own NSError subclass
return NO;
}
}
// ...
// Operation was successful.
return YES;
}
You can certainly have multiple lines in your try block. Example:
#try {
if (managedObjectContext == nil) {
actionMessage = #"accessing user recipe library";
[self initCoreDataStack];
}
actionMessage = #"finding recipes";
recipes = [self recipesMatchingSearchParameters];
actionMessage = #"generating recipe summaries";
summaries = [self summariesFromRecipes:recipes];
}
#catch (NSException *exception) {
NSMutableDictionary *errorDict = [NSMutableDictionary dictionary];
[errorDict setObject:[NSString stringWithFormat:#"Error %#: %#", actionMessage, [exception reason]] forKey:OSAScriptErrorMessage];
[errorDict setObject:[NSNumber numberWithInt:errOSAGeneralError] forKey:OSAScriptErrorNumber];
*errorInfo = errorDict;
return input;
} #catch (OtherException * e) {
....
} #finally {
// Any clean up can happen here.
// Finally will be called if an exception is thrown or not.
}
And a link to practical use of exceptions:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
Its completely alright to enclose the method call with try-catch block.
If you don't care which line caused the exception you can enclose the entire function in a try/catch block.
For example, assume that f1(), f2() or f3() can throw an exception in this code:
try {
f1();
f2();
f3();
}
catch( ... ) {
...either f1, f2 or f3 threw an exception - don't know which
}
You can include the whole method body in your try block.
In your catch part you can have multiple catch blocks to handle different types of exceptions:
#catch (NSException * e) {
....
}
#catch (OtherException * e) {
....
}
#finally {
NSLog(#"finally");
}
so you could also discern exactly which line failed based on the specific exception raised, if you ever need it.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
You can include the whole method body in your try block.

NSAssert usage in threads

I'm trying to use NSAssert throughout my iPhone app so that if an unexpected condition occurs, the application fails-fast and crashes with a meaningful message in the crash log.
This works fine if the failing NSAssert is on the main thread, as it raises NSInternalInconsistencyException by default which is uncaught and stops execution. But I'm also doing processing in background threads, in which case the NSAssert just aborts the thread, but the programming keeps running.
My current solution is to catch and rethrow the exception in the main thread (in this case, NSOperation's main method):
- (void)main {
#try {
int x = 14;
...
NSAssert1(x > 20, #"x should be greater than 20, was %d", x);
...
}
#catch (NSException *e) {
[e performSelectorOnMainThread:#selector(raise) withObject:nil waitUntilDone:YES];
}
}
Is there a better way? Perhaps using a custom NSAssertionHandler?
I know I could just use C's assert with a static annotation:
assert(x > 20 && "x should be greater than 20");
But this doesn't allow me to show what the actual failing value of x is.
You can replace the NSAssert with a test code followed by an exception raise. This way, if the assertion failed, an exception will be thrown, catched by the #catch block and re-raised on the main thread.
Note: You can even define a C macro, in order to provide a compact form.