You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi调用未内置OS X API及NSNetServiceDelegate实现方案咨询

Delphi访问未内置Mac API(以NSNetServiceDelegate为例)的实现方案

第一步:手动声明缺失的Objective-C协议接口

Delphi中OC协议对应带唯一GUID的接口,需继承自NSObjectProtocol,方法签名严格匹配原生OC定义,调用约定指定为cdecl:

uses
  Macapi.ObjectiveC, Macapi.Foundation;

type
  // 先声明NSNetService前置类型,避免编译错误
  NSNetService = interface;

  NSNetServiceDelegate = interface(NSObjectProtocol)
    ['{这里替换为你用Ctrl+Shift+G生成的唯一GUID}']
    // 服务解析成功回调,对应OC - (void)netServiceDidResolveAddress:(NSNetService *)sender
    procedure netServiceDidResolveAddress(sender: NSNetService); cdecl;
    // 服务解析失败回调,对应OC - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary<NSString *, NSNumber *> *)errorDict
    procedure netServiceDidNotResolveError(sender: NSNetService; errorDict: NSDictionary); cdecl;
    // 其他你需要用到的代理方法,全部按照OC头文件的签名依次声明
  end;

  // 补全NSNetService缺失的delegate属性声明(如果Delphi原生单元没提供的话)
  NSNetServiceClass = interface(NSObjectClass)
    ['{自行生成对应GUID}']
  end;
  NSNetService = interface(NSObject)
    ['{自行生成对应GUID}']
    procedure setDelegate(delegate: Pointer); cdecl;
    function delegate: Pointer; cdecl;
    // 其他缺失的方法、属性按OC签名补全
  end;
  TNSNetService = class(TOCGenericImport<NSNetServiceClass, NSNetService>) end;

第二步:实现代理类

继承Delphi提供的TOCLocal基类,实现刚才声明的NSNetServiceDelegate接口:

type
  TCustomNetServiceDelegate = class(TOCLocal, NSNetServiceDelegate)
  public
    procedure netServiceDidResolveAddress(sender: NSNetService); cdecl;
    procedure netServiceDidNotResolveError(sender: NSNetService; errorDict: NSDictionary); cdecl;
  end;

procedure TCustomNetServiceDelegate.netServiceDidResolveAddress(sender: NSNetService);
begin
  // 此处编写服务解析成功后的业务逻辑,可读取sender的hostName、addresses等属性获取设备信息
end;

procedure TCustomNetServiceDelegate.netServiceDidNotResolveError(sender: NSNetService; errorDict: NSDictionary);
begin
  // 此处编写服务解析失败的异常处理逻辑
end;

第三步:关联代理并调用API

注意必须持有代理类的实例,避免被自动释放导致访问异常:

type
  TMainForm = class(TForm)
    // 窗体控件声明
  private
    FNetService: NSNetService;
    FServiceDelegate: TCustomNetServiceDelegate;
  public
    procedure StartBonjourSearch;
  end;

procedure TMainForm.StartBonjourSearch;
begin
  // 初始化代理并持有引用
  FServiceDelegate := TCustomNetServiceDelegate.Create;
  // 初始化NSNetService实例,配置为搜索你指定类型的局域网服务
  FNetService := TNSNetService.Alloc.initWithDomain('', '_你的服务类型._tcp', '');
  FNetService.setDelegate(FServiceDelegate);
  FNetService.scheduleInRunLoop(NSRunLoop.currentRunLoop, NSDefaultRunLoopMode);
  FNetService.startDiscovery;
end;

注意事项

  • 所有OC方法的签名必须和Apple官方头文件完全一致,包括参数顺序、类型、返回值,调用约定必须加cdecl,否则会触发访问越界、参数异常等问题
  • 代理实例、NSNetService实例必须和使用场景的生命周期绑定,不能作为局部变量声明,否则被自动释放后回调会触发Access Violation
  • MacOS开启沙箱的情况下,需要在entitlements配置中添加Bonjour相关权限,否则服务发现会无响应
  • 其他未内置的Mac API都可以按照相同的手动绑定逻辑实现,核心是匹配OC的类型、方法签名和调用约定

内容的提问来源于stack exchange,提问作者user3820843

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 02:12:02