Trabajar con API C de Swift

Estoy intentando hacer un seguimiento del estado de la networking. Revisé el código de FXReachability . Específicamente el siguiente método.

- (void)setHost:(NSString *)host { if (host != _host) { if (_reachability) { SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFRelease(_reachability); } _host = [host copy]; _status = FXReachabilityStatusUnknown; _reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [_host UTF8String]); SCNetworkReachabilityContext context = { 0, ( __bridge void *)self, NULL, NULL, NULL }; SCNetworkReachabilitySetCallback(_reachability, ONEReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); } } 

Lo que hace es seguir comprobando la connection con el host especificado. Estoy tratando de convertir este método a Swift y estoy teniendo algunos problemas.

1. Conversión de la cadena de host a UTF8.

Tengo que convertir la cadena de host a UTF8 y pasarla al método SCNetworkReachabilityCreateWithName . No puedo encontrar el equivalente de Swift equivalente de la propiedad UTF8String en Objective-C. Pero hay una propiedad llamada utf8 para el tipo String . De acuerdo con la documentation ,

Puede acceder a una representación UTF-8 de una cadena mediante iteración sobre su propiedad utf8. Esta propiedad es de tipo String.UTF8View, que es una colección de valores de 8 bits sin signo (UInt8), uno para cada byte en la representación UTF-8 de la cadena:

¿Cómo puedo get una representación UTF8 completa de una cadena en lugar de una colección de valores de 8 bits sin signo (UInt8)?


2. Función de callback para SCNetworkReachabilitySetCallback .

El segundo parámetro de esta function espera algo de tipo SCNetworkReachabilityCallBack . Me metí en el file fuente y descubrí que en realidad es una typealias .

 typealias SCNetworkReachabilityCallBack = CFunctionPointer<((SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void)> 

Lo definí así.

 let reachabilityCallBack: SCNetworkReachabilityCallBack = { }() 

Pero obtengo el error Falta el retorno en un cierre que se espera que devuelva 'SCNetworkReachabilityCallBack' cuando en esa tipealias puede ver claramente que devuelve Void .

¿Es esta la manera incorrecta de hacer esto?


Estos son los problemas que estoy enfrentando. He estado en esto durante horas sin suerte, así que realmente agradecería cualquier ayuda.

Gracias.

Su primer problema se puede resolver con

 let reachability = host.withCString { SCNetworkReachabilityCreateWithName(nil, $0).takeRetainedValue() } 

Dentro del cierre, $0 es un puntero a la representación UTF-8 terminada en NUL de la cadena.

Actualización: Como dijo Nate Cook en una respuesta ahora eliminada y también aquí , puede pasar una cadena Swift a una function que toma un valor UnsafePointer<UInt8> directamente:

 let reachability = SCNetworkReachabilityCreateWithName(nil, host).takeRetainedValue() 

Desafortunadamente, hay (hasta donde sé) actualmente no hay solución para su segundo problema. SCNetworkReachabilitySetCallback espera un puntero a una function C como segundo parámetro, y actualmente no hay ningún método para pasar una function o cierre Swift. Tenga en count que la documentation de SCNetworkReachabilityCallBack solo muestra Objective-C pero no Swift.

Ver también ¿Swift no funciona con pointers de function? .


Actualización para Swift 2: ahora es posible pasar un cierre Swift a una function C tomando un parámetro de puntero de function. Además SCNetworkReachabilityCreateWithName() ya no devuelve un object no administrado:

 let host = "google.com" var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) let reachability = SCNetworkReachabilityCreateWithName(nil, host)! SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in print(flags) }, &context) SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes) 

Actualización para Swift 3 (Xcode 8):

 let host = "google.com" var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) let reachability = SCNetworkReachabilityCreateWithName(nil, host)! SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in print(flags) }, &context) SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)