objective-c - XPC 和异常处理

标签 objective-c cocoa cocoa-touch xpc nsxpcconnection

我有一个 LaunchAgent,使用 HockeyApp 进行崩溃报告。现在我注意到 HockeyApp 没有报告未捕获的异常,就像在普通的 macOS 应用程序中一样。

例如:

- (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply {
    NSArray *array = [NSArray array];
    reply([array objectAtIndex:23]);
}

从未到达NSUncaughtExceptionHandler,但控制台记录:

<NSXPCConnection: 0x7fe97dc0f110> connection from pid 44573: Warning: Exception caught during invocation of received message, dropping incoming message and invalidating the connection.

问题是如何获取 HockeyApp 报告的未处理异常。

最佳答案

问题:

XPC 似乎有自己的@try @catch block ,它捕获方法内未处理的异常,记录异常,然后调用-[NSXPCConnection InterruptionHandler]

此问题已通过 rdar://48543049 报告给 Apple .

注意:这些不是复制和过去的解决方案,请仔细评估您的崩溃报告框架。我链接到 PLCrashReporter 的实现细节。

解决方案A:

@try @catch block :

- (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply {
    @try {
        NSArray *array = [NSArray array];
        reply([array objectAtIndex:23]);
    } @catch (NSException *exception) {
        NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
        if (handler) {
            handler(exception);
        }
    }
}

讨论

HockeyApp 使用 PLCrashReporter 进行崩溃报告。 PLCrashReporter 注册一个 NSUncaughtExceptionHandler ( code )。因此,上面的代码会将异常转发到 PLCrashReporter 异常处理程序并终止 ( code ) XPC。

Mattie建议再次@throw异常,以触发内部XPC@catch block 以及可能的内部清理和日志记录。 这是需要考虑的事情。特别是如果您在连接的 LaunchAgent/Server 端的 NSXPCConnection 上有一个自定义的 interruptionHandler!

现在我不会再扔它了,因为我的 XPC 是完全无状态的,只要崩溃就应该没问题。

解决方案 A 的缺点是通过 XPC 公开的每个方法都需要这个@try @catch block

解决方案B:

使用 NSProxy 捕获所有未处理的异常作为 NSXPCConnection exportObject:

@interface LOUncaughtExceptionHandlerProxy : NSProxy {
    NSObject *_object;
}
@end

@implementation LOUncaughtExceptionHandlerProxy

- (instancetype)initWithObject:(NSObject *)object
{
    NSParameterAssert(object);
    _object = object;
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    return [_object methodSignatureForSelector:selector];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    @try {
        [invocation invokeWithTarget:_object];
    } @catch (NSException *exception) {
        NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
        if (handler) {
            handler(exception);
        }
    }
}

@end

NSXPCListener 监听器中进行设置:

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
    XPC *exportedObject = [XPC new];
    LOUncaughtExceptionHandlerProxy *proxy = [[LOUncaughtExceptionHandlerProxy alloc] initWithObject:exportedObject];
    newConnection.exportedObject = proxy;
    newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
    [newConnection resume];
    return YES;
}

解决方案 A 的所有详细信息均适用于解决方案 B。

解决方案Z:

在 macOS 上可以使用ExceptionHandling.framework,它的问题在 BITCrashExceptionApplication.h 中有很好的概述。 .

讨论

框架没有移植到 iOS 上绝不是一个好兆头。另请注意Matties评论:

I've had interactions with Apple that directly indicate that ExceptionHandling.framework is no longer supported. And, in my experience while working on Crashlytics, it had some fundamental interoperability issues beyond what is indicated in that quoted header.

关于objective-c - XPC 和异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54967355/

相关文章:

objective-c - 需要一个关于如何存储/加载我的自定义类以进行 iOS 开发的简单示例

objective-c - 确定哪个 NSView 实例发起了 mouseDown :

ios - 在 iOS 设备中保留批处理消息历史记录

iphone - 获取设备内存 Xcode

cocoa - 如何阻止直到 Cocoa 中发布特定通知?

ios - 一段时间后通过编码自动从相机捕获图像

iphone - 如何使用 UISearchDisplayController 预加载或初始化搜索?

objective-c - for 循环在editingStyleForRowAtIndexPath 中仅执行一次

objective-c - 为什么从用户输入中获取的两个 NSString 最终具有相同的地址?

cocoa - OSX El Capitan 上的透明 NSWindow