gpt4 book ai didi

objective-c - 如何在 OSX 中调试 XPC 服务和客户端应用程序之间的通信

转载 作者:行者123 更新时间:2023-12-03 17:27:55 25 4
gpt4 key购买 nike

我正在尝试编写一对简单的“客户端应用程序”和“XPC 服务”。我能够从客户端启动 xpc 服务(即我可以看到在事件监视器进程列表中运行的服务),但是当我尝试发送任何具有响应块的请求时,我收到一个错误:“无法与一个辅助应用程序。”

这里最糟糕的事情是错误没有给我任何关于出了什么问题的信息。而且我也无法正确调试服务。据我了解,正确的方法是将调试器附加到进程(调试->附加到进程,另见 here)。我在一个工作区中同时拥有客户和服务项目。

当我从 xcode 运行客户端并尝试将调试器附加到启动的服务时,以“无法附加到 pid:X”错误结束。

如果我存档客户端应用程序从应用程序文件运行它,然后尝试将调试器附加到服务,结果是相同的。

从我可以想象的服务中记录某些内容的唯一方法是编写一个记录器类,它将数据写入某个文件。还没有尝试过这种方法,但这对我来说看起来很疯狂。

所以我的问题是:

a) 当收到诸如“无法与辅助应用程序通信”之类的非信息性响应时,如何找出问题所在?

b) 而且,首先调试 xpc 服务的正确方法是什么?上面的链接从现在起已有 5 年历史,但是我可以看到有些人说“附加到调试器”不起作用。

代码本身相当简单:

XPC 服务,监听器实现:

#import "ProcessorListener.h"

@implementation ProcessorListener

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
[newConnection setExportedInterface: [NSXPCInterface interfaceWithProtocol:@protocol(TestServiceProtocol)]];
[newConnection setExportedObject: self];
self.xpcConnection = newConnection;

newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol: @protocol(Progress)];

// connections start suspended by default, so resume and start receiving them
[newConnection resume];

return YES;
}

- (void) sendMessageWithResponse:(NSString *)receivedString reply:(void (^)(NSString *))reply
{
reply = @"This is a response";
}

- (void) sendMessageWithNoResponse:(NSString *)mString
{
// no response here, dummy method
NSLog(@"%@", mString);
}

以及服务的主要文件:
#import <Foundation/Foundation.h>
#import "TestService.h"

@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
@end

@implementation ServiceDelegate

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
// This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.

// Configure the connection.
// First, set the interface that the exported object implements.
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(TestServiceProtocol)];

// Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
TestService *exportedObject = [TestService new];
newConnection.exportedObject = exportedObject;

// Resuming the connection allows the system to deliver more incoming messages.
[newConnection resume];

// Returning YES from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call -invalidate on the connection and return NO.
return YES;
}

@end

int main(int argc, const char *argv[])
{
// [NSThread sleepForTimeInterval:10.0];
// Create the delegate for the service.
ServiceDelegate *delegate = [ServiceDelegate new];

// Set up the one NSXPCListener for this service. It will handle all incoming connections.
NSXPCListener *listener = [NSXPCListener serviceListener];
listener.delegate = delegate;

// Resuming the serviceListener starts this service. This method does not return.
[listener resume];
return 0;
}

对于客户端应用程序,UI 包含一堆按钮:
- (IBAction)buttonSendMessageTap:(id)sender {
if ([daemonController running])
{
[self executeRemoteProcessWithName:@"NoResponse"];
}
else
{
[[self.labelMessageResult cell] setTitle: @"Error"];
}
}

- (IBAction)buttonSendMessage2:(id)sender {
if ([daemonController running])
{
[self executeRemoteProcessWithName:@"WithResponse"];
}
else
{
[[self.labelMessageResult cell] setTitle: @"Error"];
}
}

- (void) executeRemoteProcessWithName: (NSString*) processName
{
// Create connection
NSXPCInterface * myCookieInterface = [NSXPCInterface interfaceWithProtocol: @protocol(Processor)];

NSXPCConnection * connection = [[NSXPCConnection alloc] initWithServiceName: @"bunldeID"]; // there's a correct bundle id there, really

[connection setRemoteObjectInterface: myCookieInterface];

connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(Progress)];
connection.exportedObject = self;

[connection resume];

// NOTE that this error handling code is not called, when debugging client, i.e connection seems to be established
id<Processor> theProcessor = [connection remoteObjectProxyWithErrorHandler:^(NSError *err)
{
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle: @"OK"];
[alert setMessageText: err.localizedDescription];
[alert setAlertStyle: NSAlertStyleWarning];

[alert performSelectorOnMainThread: @selector(runModal) withObject: nil waitUntilDone: YES];
}];

if ([processName containsString:@"NoResponse"])
{
[theProcessor sendMessageWithNoResponse:@"message"];
}
else if ([processName containsString:@"WithResponse"])
{
[theProcessor sendMessageWithResponse:@"message" reply:^(NSString* replyString)
{
[[self.labelMessageResult cell] setTitle: replyString];
}];
}
}

最佳答案

乔纳森·莱文 XPoCe当您无法附加调试器时,该工具很有用。
您可以添加日志记录 NSLog()fprintf(stderr,...)给您的服务和客户,特别是状态代码。你只需要指定文件的路径来写入标准输出和标准错误。 <key>StandardErrorPath</key> <string>/tmp/mystderr.log</string>有一个关于 Debugging Daemons 的部分在这篇关于 objc.io 的文章中。

关于objective-c - 如何在 OSX 中调试 XPC 服务和客户端应用程序之间的通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42764618/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com