ios - Swift - 字典崩溃中的关闭

标签 ios dictionary swift crash closures

所以我有 objc 代码,它使用 Singleton 实例进行 ping(使用 SimplePing)并保存 ping 请求完成 block 。在 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 存储在 Dictionary 中并立即调用它对我不起作用:

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
        }
    }
}

正如您在代码中看到的那样,假设存在一些内存问题,我什至尝试使用主机名(它是字符串)而不是 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

    }

因此,通过简单地更改方法调用,一切都开始工作了。奇怪的是编译器没有注意到这个问题。

关于ios - Swift - 字典崩溃中的关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25912670/

相关文章:

ios - 如何在ios中的UITableview中聚焦最后一个单元格

ios - 带文件上传的摘要式身份验证

ios - 标注按钮使应用程序崩溃 - MapKit

ios - 以编程方式创建 TableView 时未显示

python - 将多个字典作为参数传递给函数

c# - 在 C# 中打印字典键值对

swift - 安装后ReactiveCocoa出错

ios - 注销按钮创建后退按钮

ios - 如何修改依赖注入(inject)模式中的对象

python - 在 Python 中阻止字典?