Reputation:
I want my application to never just crash stupidly. I know that code quality is the root solution for this. But I still need an application to never crash when some unexpected bug happens. Here is code I want to try.
-(void)testException
{
@try
{
NSString* str;
[str release];
}
@catch(NSException* ex)
{
NSLog(@"Bug captured");
}
}
I know this one does not work. Because release
never raise an exception. Here are my questions:
Here's what I have read
I come from an experienced Microsoft programmer background in which catch exception or unexpected exception always prevent my program from crashing in a very bad environment.
How did you guys/gals (Mac genius programmers) make crash free programs happened? Share your experience.
Upvotes: 9
Views: 18154
Reputation: 49364
Test Test Test Test Test
You can spend all day writing exception-handling code for possible exceptions (that in practice will never occur), or you can create thorough test suites and only write exception handlers for situations that occur in practice.
This is why I almost never write exception handlers. If you fix the underlying issues that are causing the exception, then you don't need to handle anything.
Of course, there are situations where can't ensure that a method call won't cause an exception and you need to be prepared, but wrapping everything in @try/@catch blocks is definitely not the solution.
Upvotes: 4
Reputation: 1372
Objective-C is an unmanaged runtime; the code that you compile runs directly on the CPU rather than in a virtual machine. That means you don't have the supervisory layer that can trap every possible failure mode the way you do when running in the .NET VM or the JVM. The long and short of it is that the only way you're going to be completely sure a program can't crash is to code very carefully and test very thoroughly. And even then, you're not sure, you just think you are.
The latest version of Xcode integrates the Clang static analyzer ('Build and Analyze' in the Build menu) that can identity some classes of potential bugs -- I'm fairly sure it would flag your example above, for instance). But there is no magic bullet here; the only solution is hard work.
Upvotes: 12
Reputation: 25969
One issue you are having is that str is never initialized which means that str may be pointing to nil (but this is not guaranteed). It is definitely pointing to junk.
If you step through your code, I can almost guarantee that your release is being called on nil, which in Objective-C is completely valid.
Try doing this:
NSString *str = [[NSString alloc] initWithString:@"a string"];
[str release];
[str release];
Calling release does not deallocate an object, it simply decrements the retain count by 1. When an objects retain count is 0,
[self dealloc];
is called automatically.
If the above code does not throw an exception immediately, it may be because the actual deallocation message is delayed at some future point (I'm not sure exactly when dealloc is called after the retain count reaches 0. I think it is called immediately and on the same thread, but some other Cocoa ninja will know for sure).
What you can do is add a category to NSObject and implement the dealloc and release methods and try to catch you're exception in there.
- (void)dealloc{
@try
{
[super dealloc];
}
@catch(NSException* ex)
{
NSLog(@"Bug captured");
}
}
- (void)release{
@try
{
[super release];
}
@catch(NSException* ex)
{
NSLog(@"Bug captured");
}
}
The added bonus is that this code will be valid for every object in your app since it is a category on NSObject.
To be complete though, if you just practice them memory management rules, you will be fine.
Upvotes: 3