ios - Trabajando con C API de Swift
utf-8 callback (1)
Estoy tratando de mantener un registro del estado de la red. 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 que sigue revisando la conexión al host especificado. Intento convertir este método en Swift y tengo un par de problemas.
1. Convertir 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 Swift exacto de la propiedad UTF8String
en Objective-C. Pero hay una propiedad llamada utf8
para el tipo String
. De acuerdo con la documentación ,
Puede acceder a una representación UTF-8 de una Cadena al iterar sobre su propiedad utf8. Esta propiedad es de tipo String.UTF8View, que es una colección de valores de 8 bits sin firmar (UInt8), uno para cada byte en la representación UTF-8 de la cadena:
¿Cómo puedo obtener una representación completa de UTF8 de una cadena en lugar de una colección de valores de 8 bits sin firmar (UInt8)?
2. Función de devolución de llamada para SCNetworkReachabilitySetCallback .
El segundo parámetro de esta función espera algo del tipo SCNetworkReachabilityCallBack
. Me sumergí en el archivo de origen y descubrí que en realidad se trata de una typealias
.
typealias SCNetworkReachabilityCallBack = CFunctionPointer<((SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void)>
Lo definí así.
let reachabilityCallBack: SCNetworkReachabilityCallBack = {
}()
Pero obtengo el error Falta retorno en un cierre que se espera que devuelva ''SCNetworkReachabilityCallBack'' cuando en esas typealias se 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 del String.
Actualización: como dijo Nate Cook en una respuesta ahora eliminada y también aquí , puedes pasar una cadena Swift a una función tomando un UnsafePointer<UInt8>
directamente:
let reachability = SCNetworkReachabilityCreateWithName(nil, host).takeRetainedValue()
Desafortunadamente, (hasta donde yo sé) actualmente no hay solución para su segundo problema. SCNetworkReachabilitySetCallback
espera un puntero a una función C como segundo parámetro, y actualmente no hay ningún método para pasar una función o cierre Swift. Tenga en cuenta que la documentación de SCNetworkReachabilityCallBack
muestra solo Objective-C pero no Swift.
Consulte también ¿Swift no funciona con punteros de función? .
Actualización para Swift 2: ahora es posible pasar un cierre Swift a una función C tomando un parámetro de puntero a función. Además, SCNetworkReachabilityCreateWithName()
ya no devuelve un objeto 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)