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];
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM