views:

2119

answers:

3

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:

  1. How to reach this kind of objective, bug will be captured, no crash?
  2. How do I know which system library will raise exception and so I can write some code and know it works?

Here's what I have read

  • a. Exception Programming Topics for Cocoa
  • b. Error Handling Programming
    Guide For Cocoa

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.

A: 

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.

Corey Floyd
Thanks for your answer. Your answer help me better understand memory management and extend my knowledge about Objective C. However, I have tried the code, they never crash (They should be, I release 4 times, reference count should be -3 if possible). but no crash happened at all, no exception throw also.I know it will crash sometime. but dont know when. so back to basic, is there a way to avoid crash?
Don't be concerned with retain counts. You should never check it, it is never what you think it should be for various reasons. You must take care of memory management one method at a time. Search Stackoverflow and google for cocoa memory management. There are plenty of resources to help you. It can be hard to learn at first, but becomes more automatic.
Corey Floyd
+1  A: 

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.

Skirwan
A: 

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.

kubi