zoukankan      html  css  js  c++  java
  • Objective C XPC 初步学习<二>

    前面有对xpc进行一些学习了解,这篇主要是记录下xpc的创建以及使用过程。

    一、创建xpc target

    新建project-->targets,左下角点➕搜索xpc,点击next添加即可,设定xpc bundle 名称,后面需要bind 连接。

    二、代码实现

    添加完xpc之后,项目内会出现xpc service的source 包,这里用来实现你的xpc功能需求,我这边新增了一个client 应来处理sevice的响应,代码如下:

    Sevice端:

    main.m

    
    #import <Foundation/Foundation.h>
    #import "xpcService.h"
    #import "xpcClient.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.
        //设置service端接收消息的配置
        newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcServiceProtocol)];
        
        // 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.
        xpcService *exportedObject = [xpcService new];
        newConnection.exportedObject = exportedObject;
        
        
        newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcClientProtocol)];
        exportedObject.xpcConnect = newConnection;
        // 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[])
    {
        // 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;
    }
    

    xpcServiceProtocol.h

    
    #import <Foundation/Foundation.h>
    
    // The protocol that this service will vend as its API. This header file will also need to be visible to the process hosting the service.
    @protocol xpcServiceProtocol
    
    // Replace the API of this protocol with an API appropriate to the service you are vending.
    - (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply;
        
    - (void)sendToClient:(NSString *)info withReply:(void (^)(NSString *))reply;
    
    @end
    

    xpcService.h

    #import <Foundation/Foundation.h>
    #import "xpcServiceProtocol.h"
    #import "xpcClient.h"
    // This object implements the protocol which we have defined. It provides the actual behavior for the service. It is 'exported' by the service to make it available to the process hosting the service over an NSXPCConnection.
    @interface xpcService : NSObject <xpcServiceProtocol>
    @property(nonatomic,strong) id<xpcClientProtocol> service;
    
    @property NSXPCConnection *xpcConnect;
    
    @end
    

    xpcService.m

    #import "xpcService.h"
    
    @implementation xpcService
    
    // This implements the example protocol. Replace the body of this class with the implementation of this service's protocol.
    - (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply {
        NSString *response = [aString uppercaseString];
        reply(response);
    }
    
    - (void)sendToClient:(NSString *)info withReply:(void (^)(NSString *))reply {
        reply(@"[Server]:");
        [[_xpcConnect remoteObjectProxy] getMsgFromService:@"this is ping test from server"];
    }
    
    
    @end
    

    Client端:

    xpcClientProtocol.h

    -->协议的创建,点击项目里面,command+n或者右键新增,选择objectivec-c file,选择类型为protocol

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol xpcClientProtocol <NSObject>
    
    - (void)getMsgFromService:(NSString *)message;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    xpcClient.h

    #import <Foundation/Foundation.h>
    #import "xpcClientProtocol.h"
    #import "xpcServiceProtocol.h"
    
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface xpcClient : NSObject<xpcClientProtocol>
    @property NSXPCConnection *connectionToService;
    @property (nonatomic,strong) id<xpcServiceProtocol> service;
    
    
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    xpcClient.m

    
    #import "xpcClient.h"
    
    @implementation xpcClient
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            [self createConnect];
        }
        return self;
    }
    
    -(void)createConnect{
           _connectionToService = [[NSXPCConnection alloc] initWithServiceName:@"xiaoqiang.xpcService"];
           _connectionToService.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcServiceProtocol)];
           _connectionToService.exportedObject = self;
           _connectionToService.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcClientProtocol)];
           _service = [self.connectionToService remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
                 //这里面是错误处理的代码
             }];
        
        //可以通过remoteObjectProxy获得protocol
        [[_connectionToService remoteObjectProxy] upperCaseString:@"hello ,xiaoqiang" withReply:^(NSString* reply){
            NSLog(@"result from server: %@", reply);
        }];
        
        [_connectionToService resume];
    
    }
    - (void)getMsgFromService:(nonnull NSString *)message {
         NSLog(@"server Reply:%@",message);
    }
    
    
    @end
    

    ViewController.m

    
    #import "ViewController.h"
    #import "xpcClient.h"
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        xpcClient *xpc = [[xpcClient alloc]init];
        [xpc.service upperCaseString:@"hello,world" withReply:^(NSString * reply){
            NSLog(@"result :%@",reply);
        }];
        [xpc.service sendToClient:@"Receive:" withReply:^(NSString *reply){
            NSLog(@"----->%@",reply);
    
        }];
        // Do any additional setup after loading the view.
    }
    
    
    - (void)setRepresentedObject:(id)representedObject {
        [super setRepresentedObject:representedObject];
    
        // Update the view, if already loaded.
    }
    
    

    最后编译执行,你就会看到sevice 呼叫,client接收的信息。

    2020-07-21 14:29:45.373534+0800 XpcTest[10121:122917] result from server: HELLO ,XIAOQIANG
    2020-07-21 14:29:45.373713+0800 XpcTest[10121:122917] result :HELLO,WORLD
    2020-07-21 14:29:45.373856+0800 XpcTest[10121:122917] ----->[Server]:
    2020-07-21 14:29:45.373930+0800 XpcTest[10121:122917] server Reply:this is ping test from server
    
    

    XPC 属性

    前面如果看的不是很明白的话,在来解释下xpc的应用过程

    前面用到了2种方法来调用远端方法

    1.xpcServiceProtocol 属性

    @property (nonatomic,strong) id<xpcServiceProtocol> service;
    -->
    xpcClient *xpc = [[xpcClient alloc]init];
    [xpc.service upperCaseString:@"hello,world" withReply:^(NSString * reply){
        NSLog(@"result :%@",reply);
    }];
    
    

    2.NSXPCConnection 属性remoteObjectProxy调用远端方法

    @property NSXPCConnection *connectionToService;
    -->
    [[_connectionToService remoteObjectProxy] upperCaseString:@"hello ,xiaoqiang" withReply:^(NSString* reply){
          NSLog(@"result from server: %@", reply);
      }];
    

    根据这张图,来解析一下client和main.m所做的事情:

    过程:

    Service端:
    1.首先,设置导出对象实现的接口,也就是service协议
    -->newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcServiceProtocol)];
    
    2.接下来,设置连接导出的对象。在与此服务的连接上发送的所有消息都将发送到导出的对象进行处理(xpcService)。连接保留导出的对象。
     --> xpcService *exportedObject = [xpcService new];
        newConnection.exportedObject = exportedObject;
        newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcClientProtocol)];
        exportedObject.xpcConnect = newConnection;
    
    3.恢复连接允许系统传递更多的传入消息。
     -->[newConnection resume];
    
    Client端:
    @property NSXPCConnection *connectionToService;
    1.设定当前xpc服务名称,并设定远端service接口,也就是sevice协议。
    _connectionToService = [[NSXPCConnection alloc] initWithServiceName:@"xiaoqiang.xpcService"];
    
    _connectionToService.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcServiceProtocol)];
    
    2.将自己设置为导出对象,目的是为了在当前同一xpcConnection属性下供对方获得接口内容(这里的client有定义一个协议方法,暴露给remote sevice)。  
    _connectionToService.exportedObject = self;
    _connectionToService.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(xpcClientProtocol)];
    
    3.这一步很重要,通过remoteObjectProxyWithErrorHandler返回一个代理对象,如果连接发生错误,它将调用错误处理块。如果发送给代理的消息具有reply处理程序,则错误处理程序或reply处理程序将仅被调用一次.
    _service = [self.connectionToService remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
                 //错误处理的代码
     }];
    
    4.通过remoteObjectProxy获得protocol方法实现,最后resume整个xpc 连接.
    [[_connectionToService remoteObjectProxy] upperCaseString:@"hello ,xiaoqiang" withReply:^(NSString* reply){
        NSLog(@"result from server: %@", reply);
    }];
        
    [_connectionToService resume];
        
    
  • 相关阅读:
    Vue开源项目库汇总【壮灬哥出品,必为精品】
    nginx配置
    找出判断数据是否有相同的值
    CSS设置文字不能被选中
    js怎么删数组固定的值
    IO流中File文件最常用和直接的用法
    JComboBox实现当前所选项功能和JFrame窗口释放资源的dispose()方法
    java中经常使用的Swing组件总结
    JTextArea利用JScrollpane增加文本域滚轮(滚动条)
    JFrame关闭程序就退出的设置
  • 原文地址:https://www.cnblogs.com/xiaoqiangink/p/13355210.html
Copyright © 2011-2022 走看看