I am trying to call a function when the internet connection is restored and the updateOnConnection
variable is true. Here is my code:
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)
}
My problem is that the lines:
if self.updateOnConnection {
self.refreshWallpaper()
}
cause the error: "A C function pointer cannot be formed from a closure that captures context
"
I am not sure how to check the state of updateOnConnection
and call refreshWallpaper()
in the closure that monitors changes in the internet connection. How can I fix this, or is there a totally different workaround I should be using?
Similar as in How to use instance method as callback for function which takes only func or literal closure, you have to convert
self
to a void pointer, store that in the context,
and convert it back to an object pointer in the closure:
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)
}
See also How to cast self to UnsafeMutablePointer<Void> type in swift for more details about this mechanism.
Remark: if flags.rawValue == 0
can be expressed slightly more
elegant as if flags.isEmpty
, but what you actually should
check is if flags.contains(.Reachable)
.
Update for 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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With