所以我有objc代码,该代码使用Singleton实例进行ping(使用SimplePing)并保存ping请求完成块。在ObjC中,它看起来像这样:

@interface SimplePingClient()
{
    NSMutableArray* _currentPings;
    NSMutableDictionary* _currentCallbacks;
}

@end

@implementation SimplePingClient

-(id)init
{
    if( self = [super init] )
    {
        _currentPings = [NSMutableArray new];
        _currentCallbacks = [NSMutableDictionary new];
    }

    return self;
}

开始ping的方法:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
{
    TSimplePing* pingClient = [TSimplePing simplePingWithHostName:hostName];
    [_currentPings addObject:pingClient];
    [_currentCallbacks setObject:result forKey:[NSValue valueWithNonretainedObject:pingClient]];
    pingClient.delegate = self;
    //some other irrelevant code
    ...
}

当调用SimplePing委托(delegate)方法时:
- (void)simplePing:(TSimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet
{
    void(^callback)(NSString* latency) = [_currentCallbacks objectForKey:[NSValue valueWithNonretainedObject:pinger]];
    if( callback )
    {
        //some irrelevant code
        ...
        callback(@"123");//hard coded for test, irrelevant code get this value correctly ;)
        [_currentCallbacks removeObjectForKey:[NSValue valueWithNonretainedObject:pinger]];
    }
    [_currentPings removeObject:pinger];
}

因此,此代码可在objc上完美运行。但是,当我尝试在Swift中移植它时,我总是收到错误EXC_BAD_ACCESS。为了简化示例,我只是擦除了所有内容,结果发现在字典中存储Closure并立即调用它对我不起作用:
typealias callbackClosure = (String) -> ()

class SimplePingClient: NSObject
{
    // MARK: variables
    var _currentPings = [TSimplePing]()
    var _currentCallbacks: Dictionary<String, callbackClosure> = [String: callbackClosure]()

    private func ping(hostname: String, resultCallback:callbackClosure)
    {
        var pingClient = TSimplePing(hostName: hostname)
        pingClient.delegate = self
        _currentPings.append(pingClient)
        _currentCallbacks[pingClient.hostName] = resultCallback

        if let callback = _currentCallbacks[pingClient.hostName]
        {
            callback("123213")//here program CRASHES
        }
    }
}

如您在代码中所看到的,假设某些内存问题,我什至尝试使用主机名(即String)而不是NSValue,但事实并非如此-仍然崩溃。但是,此错误肯定与内存管理有关,但是我无法理解我在做什么。如果有人能指出我所缺少的内容,我将不胜感激。

最佳答案

正如@Owen Hartnett所建议的那样,我将解决方案从答案本身移到这里:

好的,经过一个小时的调试,事实证明原因很愚蠢。正如我说的那样,我正在移植代码,因此以前我将此类用作桥接的objective-c代码,因此该功能:

-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result

通过以下方式桥接:
SimplePingClient.pingHostname(latencyUrl, refreshTime: refreshRate) { (latency: String!) -> () in

   if nil != latency
   {
       //dummy code
   }

}

因此,在SimplePingClient成为swift类之后,我新的闭包签名是(请注意,现在延迟不是强制展开的,并且不是可选的,并且也不需要检查nil)
SimplePingClient.pingHostname(latencyUrl, refreshTime: refreshRate) { (latency: String) -> () in

       //dummy code

    }

因此,只需更改方法调用即可开始一切工作。编译器没有注意到此问题的奇怪之处。

10-05 20:53
查看更多