【问题标题】:NSConnection - how to properly do "unvending" of an object?NSConnection - 如何正确地“取消”对象?
【发布时间】:2015-09-22 11:08:29
【问题描述】:

对于 Mac OSX,我尝试使用 NSConnection 代理对象从一个应用程序实例到同一主机上的另一个应用程序实例的访问。相关代码如下。如果需要,我可以提供更多。假设当我说“服务器”时,我指的是实际使用 NSConnection 来“销售”对象的应用程序。而“客户端”是同一应用程序的另一个实例,它获得了它的代理。

一切正常,除了两个问题。

  1. 当充当服务器的应用程序尝试拆除它正在出售的对象时,任何通过代理连接的客户端仍然存在。也就是说,即使在我调用下面的stopLocalServer 函数之后,之前连接并获得代理对象的任何客户端应用程序仍然能够发送消息并调用服务器应用程序上的代码。在服务器调用NSConnection:invalidate 后,我希望客户端在传递消息时抛出异常。如何在不退出服务器进程的情况下强制断开任何客户端?

  2. 1234563这很好。但是,如果服务器通过下面的startLocalServer 代码开始出售对象,然后使用stopLocalServer 停止出售它,则后续客户端连接尝试将挂起(永远阻塞),直到服务器应用程序进程退出。对 NSConnection:connectionWithRegisteredName 的调用返回一个非零对象,但对 [_clientConnection rootProxy] 的调用将永远挂起,直到服务器应用程序实际退出。

我怀疑我没有正确地拆除原始的 NSConnection 对象,或者我在这里遗漏了一些基本的东西。

以下是我的用户界面代码所在平台的一些相关代码:

-(void)startLocalServer:(NSString*)str
{
    [self stopLocalServer];  // clean up any previous instance that might be running
    _serverConnection = [NSConnection new];
    [_serverConnection setRootObject:self];
    [_serverConnection registerName:str];
}
-(void)stopLocalServer
{
    [_serverConnection registerName:nil];
    [_serverConnection setRootObject:nil];
    [_serverConnection invalidate];
    _serverConnection = nil;
}

-(void)startClientConnection:(NSString*)str
{
    [self stopClientConnection];  // tear down any previous connection

    _clientConnection = [NSConnection connectionWithRegisteredName:str host:nil];

    if ((_clientConnection == nil) || (_clientConnection.valid == NO))
    {
        LogEvent(@"ERROR - _clientConnection is nil or invalid!");
    }
    else
    {
        _proxy = [_clientConnection rootProxy];
    }
}

-(void)stopClientConnection
{
    _proxy = nil;
    [_clientConnection invalidate];
    _clientConnection = nil;
}

【问题讨论】:

  • 为了让客户端不会像您描述的那样挂起,通常会设置超时,这可能与NSConnectionDidDieNotification等观察者相关联。
  • 好主意。在生产代码中,超时和 try/catch 块都是使用 NSConnection 代码的必备条件。超时不会解决 #1。但我想我找到了一个满足 #1 和 #2 的答案。

标签: objective-c macos distributed-objects nsconnection


【解决方案1】:

回答我自己的问题。我仍然会坚持一个更好的答案,或者是否有人可以更好地解释为什么需要这样做的原因。

我相信stopLocalServer 函数需要调用[[_serverConnection receivePort] invalidate] 以便关闭使用连接创建的端口。只需将该行添加到原始 stopLocalServer 函数即可解决我的问题。这会阻止进一步的连接尝试和消息成功。

更恰当地说,应用程序调用可以只拥有 NSConnection 使用的端口。所以这成为启动和停止分布式对象侦听器的更好解决方案:

-(void)startLocalServer:(NSString*)str
{
    [self stopLocalServer];  // clean up any previous instance that might be running
    _port = [NSPort port];   // _port is of type NSPort*
    _serverConnection = [NSConnection connectionWithReceivePort:_port sendPort:nil];
    [_serverConnection setRootObject:self];
    [_serverConnection registerName:str];
}


-(void)stopLocalServer
{
    [_serverConnection registerName:nil];
    [_serverConnection setRootObject:nil];
    [_serverConnection invalidate];
    _serverConnection = nil;

    [_port invalidate];
    _port = nil;
}

这似乎解决了上面的#1 和#2。

【讨论】:

  • 就个人而言,我会先使连接无效,然后再使端口无效。从连接下使端口无效似乎是个坏主意。另外,请注意-registerName: 的文档说只有基于NSSocketPort 的连接支持注销。另一种方法可能是使用NSConnectionDelegate 方法加上观察NSConnectionDidDieNotification 来跟踪从您的连接产生的子连接,并在您停止服务器时使这些子连接无效。
猜你喜欢
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 2013-10-18
  • 2023-03-23
  • 1970-01-01
  • 2021-02-07
  • 2017-05-18
  • 2015-04-24
相关资源
最近更新 更多