如何在Delphi中用NSNetService实现OSX Bonjour服务发布并修复访问报错
问题根因
你遇到的访问越界错误由两个核心问题导致:
- 你自定义的
NSNetService接口缺失了必要的实例初始化方法声明,OC对象alloc申请内存后必须调用init系列方法完成初始化才能使用,没有对应方法声明时调用会触发非法内存访问。 - 你直接将未初始化的
alloc返回值 Wrap 为接口实例,未完成初始化流程就调用后续方法。
修复步骤
步骤1:补全接口声明
在你定义的NSNetService接口中补充初始化方法:
NSNetService = interface(NSObject) ['{8FACC18E-5DFA-4526-A256-DBD7CF74B65C}'] // 补充这行初始化方法声明 function initWithDomain(domain: NSString; type: NSString; name: NSString; port: NSInteger): NSNetService; cdecl; // 原有其他方法声明保留不变 function TXTRecordData: NSData; cdecl; // ... 其余原有代码不用改 end;
步骤2:修改实例化与发布逻辑
修改Activate方法的实例化流程,同时补充RunLoop调度逻辑(NSNetService必须加入运行循环才能正常工作):
function TsdBonjourAnnouncerMac.Activate: Boolean; var allocPtr: Pointer; begin inherited; Result := False; // 1. 申请内存 allocPtr := TNSNetService.OCClass.alloc; if allocPtr = nil then Exit; // 2. 完成初始化,参数根据你的实际服务配置修改 INetService := TNSNetService.Wrap( TNSNetService(allocPtr).initWithDomain( NSSTR(''), // 空字符串代表使用系统默认域名 NSSTR('_http._tcp.'), // 替换为你实际的服务类型,格式为_服务名._传输协议. NSSTR('MyCustomService'), // 替换为你要广播的服务名称 9000 // 替换为你的服务实际监听端口 ) ); if INetService = nil then Exit; // 3. 设置代理 IDelegate := TsdServiceDelegate.Create; INetService.setDelegate(NSNetServiceDelegate((IDelegate as ILocalObject).GetObjectID)); // 4. 将服务加入主线程运行循环,否则无法正常广播和处理事件 INetService.scheduleInRunLoop(NSRunLoop.mainRunLoop, NSDefaultRunLoopMode); // 5. 发布服务 INetService.publish; Result := True; end;
步骤3:补充销毁逻辑
在DeActivate方法中补充资源释放逻辑,避免内存泄漏:
procedure TsdBonjourAnnouncerMac.DeActivate; begin if Assigned(INetService) then begin INetService.stop; INetService.removeFromRunLoop(NSRunLoop.mainRunLoop, NSDefaultRunLoopMode); INetService := nil; end; IDelegate := nil; inherited; end;
额外说明
你之前遇到的无法调用NSNetService方法的问题,本质是接口声明缺失导致的,补全所有你需要用到的方法声明后,即可通过实例正常调用实例方法,类方法通过TNSNetService.OCClass.方法名的格式调用即可。
内容的提问来源于stack exchange,提问作者user3820843
相关产品推荐
相关产品推荐

