Swift:将数据传递给捕获上下文的闭包

时间:2015-11-05 17:36:30

标签: swift macos cocoa

我正在尝试在恢复互联网连接并且updateOnConnection变量为真时调用函数。这是我的代码:

func checkForConnection() {
    let host = "reddit.com"
    var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
    let reachability = SCNetworkReachabilityCreateWithName(nil, host)!

    SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in
        if flags.rawValue == 0 { //internet is not connected

        } else { //internet became connected
            if self.updateOnConnection {
                self.refreshWallpaper()
            }
        }
    }, &context)

    SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)
}

我的问题是:

        if self.updateOnConnection {
            self.refreshWallpaper()
        }

导致错误:“A C function pointer cannot be formed from a closure that captures context

我不确定如何检查updateOnConnection的状态,并在监视互联网连接变化的闭包中调用refreshWallpaper()。我该如何解决这个问题,或者我应该使用完全不同的解决方法?

1 个答案:

答案 0 :(得分:17)

How to use instance method as callback for function which takes only func or literal closure类似,您必须转换 self到void指针,将其存储在上下文中, 并将其转换回闭包中的对象指针:

func checkForConnection() {

    let host = "reddit.com"
    var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
    context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())

    let reachability = SCNetworkReachabilityCreateWithName(nil, host)!

    SCNetworkReachabilitySetCallback(reachability, { (_, flags, info) in
        if flags.rawValue == 0 { //internet is not connected

        } else { //internet became connected
            let mySelf = Unmanaged<ViewController>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

            if mySelf.updateOnConnection {
                mySelf.refreshWallpaper()
            }
        }
        }, &context)

    SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)
}

另见How to cast self to UnsafeMutablePointer<Void> type in swift 有关此机制的更多详细信息。

备注: if flags.rawValue == 0可以稍微表达一下 优雅if flags.isEmpty,但实际应该是什么 检查是if flags.contains(.Reachable)

Swift 3更新(Xcode 8 beta 6):

func checkForConnection() {

    let host = "reddit.com"
    var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
    context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())

    let reachability = SCNetworkReachabilityCreateWithName(nil, host)!

    SCNetworkReachabilitySetCallback(reachability, { (_, flags, info) in
        if let info = info {
            if flags.rawValue == 0 { //internet is not connected

            } else { //internet became connected
                let mySelf = Unmanaged<ViewController>.fromOpaque(info).takeUnretainedValue()
                // ...
            }
        }
    }, &context)

    SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
}