使用NSSetUncaughtExceptionHandler在Objective C中注册未捕获异常处理程序

6

我使用UncaughtExceptionHandler注册未捕获异常处理程序的代码如下,您认为会有潜在问题吗?

@interface AppDelegate ()

void myHandler(NSException * exception);

@end

@implementation AppDelegate

void myHandler(NSException * exception)
{
  // ...
}

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(&myHandler);
..

有没有更简洁的写法呢?

我需要使用类扩展来声明原型,以消除函数无先前原型的警告

3个回答

11

Martin的回答是正确的。然而,我想稍微解释一下,为什么是这样。

您的函数定义:

void myHandler(NSException * exception)
{
  // ...
}

定义了一个可供外部使用的函数。换句话说,将在目标文件中创建一个符号,以便链接器可以找到它,从而允许其他文件调用 myHandler

然而,由于它应该是可供外部使用的,因此其他文件需要知道该函数的外观。这就是原型的作用。警告基本上是在说...

  

嘿,你已经声明了这个函数可供其他代码外部访问,但我没有看到其他代码可以使用以了解该函数信息的原型。

所以,你会收到一个警告。这是一个很好的警告。它会帮助你记得为想要导出的函数声明原型。

现在,正如您发现的那样,您可以声明原型,然后警告消失了。但是,在实现文件中仅声明原型对您来说也应该是另一个警告。个人警告应该是:

您真的希望这个函数具有外部可见性,还是仅在这个编译单元中调用?如果该函数不会具有外部可见性,则无需在符号表中导出该函数,并且其他模块可以包括以了解该函数的原型。

在这种情况下,您可以像Martin的响应中那样声明函数为 static

static void myHandler(NSException * exception)
{
  // ...
}
在这种情况下,static告诉编译器以下内容:

嘿,编译器,在此函数中创建代码,并允许此编译单元中的任何代码看到该函数,但不要使其对外可见。我不希望其他模块调用该函数。

在这种情况下,即使其他代码声明了原型,它们也无法看到您的函数,因为它是“私有”的,仅限于定义它的文件中。
由于它仅在本地文件中使用,因此不需要原型,因此也没有必要警告您没有原型。
现在只是一条注释...... 您不需要将C函数放入代码的@interface和@implementation部分中,因为那样不起任何作用。那些C函数无论是在ObjC部分内还是外都具有完全相同的可见性和访问权限。
最后,如果您愿意,可以在Xcode构建设置中禁用此警告(但既然您理解了警告的上下文,我建议将其打开)。

1
感谢您详细的解释,但是针对我的问题,myHandler 已在 AppDelegate 中注册,但未捕获的异常可能发生在任何类中,因此我不确定是否适合使用 static - Ryan
2
@Yoga:你可以在这里毫不犹豫地使用static,因为你将myHandler的地址传递给了NSSetUncaughtExceptionHandler。 可见性只对链接器很重要。 如果任何模块都有myHandler的地址,则可以独立于可见性调用此函数。- 将局部静态函数的地址传递给其他函数是一种常见模式,例如回调函数等。 - Martin R

3

如果将函数声明为static,则不会收到有关缺少原型的警告:

static void myHandler(NSException * exception)
{
  // ...
}

0

是的,这是正确的方法。我只是在想为什么你会得到警告,因为我有同样的事情,没有在空类别中声明它,但我没有得到警告... 此外,您还可以设置信号处理程序来捕获 SIGABRTSIGILLSIGBUS 信号:

void signalHandler(int sig) {

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    struct sigaction newSignalAction;
    memset(&newSignalAction, 0, sizeof(newSignalAction));
    newSignalAction.sa_handler = &signalHandler;
    sigaction(SIGABRT, &newSignalAction, NULL);
    sigaction(SIGILL, &newSignalAction, NULL);
    sigaction(SIGBUS, &newSignalAction, NULL);
    ...
}

1
我敢打赌你在编译设置中禁用了警告。 - Jody Hagins
哎呀,是的,我一定忘了 :) - graver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接