简体   繁体   English

iPhone开发:如何在Objective-C中捕获异常/ NSError?

[英]iPhone development: How to Catch Exception/NSError in Objective-C?

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. 因为release永远不会引发异常。 Here are my questions: 这是我的问题:

  1. How to reach this kind of objective, bug will be captured, no crash? 如何达到这种目标,将捕获bug,不会崩溃?
  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 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. 我来自一个经验丰富的Microsoft程序员背景,其中catch异常或意外异常总是阻止我的程序在非常糟糕的环境中崩溃。

How did you guys/gals (Mac genius programmers) make crash free programs happened? 你们/ gals(Mac天才程序员)是如何制作无崩溃程序的? Share your experience. 分享您的经验。

Objective-C is an unmanaged runtime; Objective-C是一个非托管运行时; the code that you compile runs directly on the CPU rather than in a virtual machine. 您编译的代码直接在CPU上运行,而不是在虚拟机中运行。 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. 这意味着您没有可以像在.NET VM或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). 最新版本的Xcode集成了Clang静态分析器(“构建”菜单中的“构建和分析”),可以识别某些类别的潜在错误 - 例如,我很确定它会标记上面的示例。 But there is no magic bullet here; 但这里没有灵丹妙药; the only solution is hard work. 唯一的解决方案就是努力工作。

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. 当然,有些情况下无法确保方法调用不会导致异常并且您需要做好准备,但将所有内容包装在@ try / @ catch块中绝对不是解决方案。

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). 你遇到的一个问题是str永远不会被初始化,这意味着str可能指向nil(但这不能保证)。 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. 如果您单步调试代码,我几乎可以保证您的版本在nil上调用,在Objective-C中完全有效。

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, 调用释放不释放对象,它只是将保留计数减1.当对象保留计数为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). 如果上面的代码没有立即抛出异常,可能是因为实际的释放消息在某个未来的某个时间点被延迟了(我不确定在保留计数达到0之后何时调用dealloc。我认为它会被立即调用在同一个线程上,但其他一些Cocoa忍者肯定会知道)。

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. 你可以做的是为NSObject添加一个类别并实现dealloc和release方法,并尝试在那里捕获你的异常。

- (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. 额外的好处是,此代码对您应用中的每个对象都有效,因为它是NSObject上的一个类别。

To be complete though, if you just practice them memory management rules, you will be fine. 尽管如此,如果你只是练习它们的内存管理规则,你会没事的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM