19

XPC サービスを作成し、メイン アプリケーションからメッセージを送信して XPC サービスと通信することに成功しました。しかし、私が知りたいのは、XPC サービスからメイン アプリケーションへの通信を開始できるかどうかです。Appleのドキュメントによると、XPC は双方向です。誰かが例を挙げて正しい方向に向けることができれば幸いです。

ご注意ください、

  • XPC をメイン アプリケーションから起動したい。
  • メインアプリケーションから XPC と通信します。
  • イベントが発生すると、XPC はメイン アプリケーションにメッセージを送信する必要があります。

最初の 2 つは成功しましたが、3 番目のリソースは見つかりませんでした。

ありがとう。:)

4

1 に答える 1

23

Figured everything out. The following should be a decent example:

ProcessorListener.h (included in both client and server):

@protocol Processor

- (void) doProcessing: (void (^)(NSString *response))reply;

@end

@protocol Progress

- (void) updateProgress: (double) currentProgress;
- (void) finished;

@end

@interface ProcessorListener : NSObject<NSXPCListenerDelegate, Processor>

@property (weak) NSXPCConnection *xpcConnection;

@end

ProcessorListener.m: (Included in just the server)

#import "ProcessorListener.h"

@implementation ProcessorListener

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
    [newConnection setExportedInterface: [NSXPCInterface interfaceWithProtocol:@protocol(Processor)]];
    [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) doProcessing: (void (^)(NSString *g))reply
{
    dispatch_async(dispatch_get_global_queue(0,0), ^{
      for(int index = 0; index < 60; ++index)
      {
         [NSThread sleepWithTimeInterval: 1];
         [[self.xpcConnection remoteObjectProxy] updateProgress: (double)index / (double)60 * 100];
      }

      [[self.xpcConnection remoteObjectProxy] finished];
    }

    // nil is a valid return value.
    reply(@"This is a reply!");
}

@end

MainApplication.m (your main app):

#import "ProcessorListener.h"

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

    NSXPCConnection * connection = [[NSXPCConnection alloc] initWithServiceName: kServiceName];

    [connection setRemoteObjectInterface: myCookieInterface];

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

    [connection resume];

    id<Processor> theProcessor = [connection remoteObjectProxyWithErrorHandler:^(NSError *err)
                       {
                           NSAlert *alert = [[NSAlert alloc] init];
                           [alert addButtonWithTitle: @"OK"];
                           [alert setMessageText: err.localizedDescription];
                           [alert setAlertStyle: NSWarningAlertStyle];

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

    [theProcessor doProcessing: ^(NSString * response)
     {
        NSLog(@"Received response: %@", response);
     }];
}

#pragma mark -
#pragma mark Progress

- (void) updateProgress: (double) currentProgress
{
    NSLog(@"In progress: %f", currentProgress);
}

- (void) finished
{
    NSLog(@"Has finished!");
}

@end

Note that this code is is a condensed version based on my working code. It may not compile 100% but shows the key concepts used. In the example, the doProcessing runs async to show that the callbacks defined in the Progress protocol still get executed even after the initial method has return and the Received response: This is a reply! has been logged.

于 2014-03-04T12:32:51.197 に答える