2014-11-26 2 views
3

Я пытаюсь отслеживать состояние сети. Я прошел через код FXReachability. В частности, следующий метод.Работа с C API из Swift

- (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); 
    } 
} 

Что он делает, это проверка связи с указанным хостом. Я пытаюсь преобразовать этот метод в Swift, и у меня есть пара проблем.

1. Преобразование строки хоста в UTF8.

Мне нужно преобразовать строку хоста в UTF8 и передать ее в метод SCNetworkReachabilityCreateWithName. Я не могу найти точный эквивалент Swift UTF8String недвижимости в Objective-C. Но есть свойство, называемое utf8 для типа String. Согласно documentation,

Вы можете получить представление UTF-8 строки String, итерируя ее свойство utf8. Это свойство имеет тип String.UTF8View, который представляет собой набор из неподписанных 8-битных значений (Uint8), один для каждого байта в UTF8 представлении струны:

Как я могу получить полное представление UTF8 строка вместо набора 8-битных (UInt8) значений без знака?


2. Функция обратного вызова для SCNetworkReachabilitySetCallback.

Второй параметр этой функции ожидает что-то типа SCNetworkReachabilityCallBack. Я погрузился в исходный файл и узнал, что это на самом деле typealias.

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

Я определил его следующим образом.

let reachabilityCallBack: SCNetworkReachabilityCallBack = { 

}() 

Но я получаю ошибку Missing возвращение в закрытие ожидается возвращение «SCNetworkReachabilityCallBack» когда в этом typealias вы можете ясно видеть, что она возвращает Void.

Это неправильный способ сделать это?


Это проблемы, с которыми я сталкиваюсь. Я был в этом часом сейчас без везения, поэтому я бы очень признателен за любую помощь.

спасибо.

+0

@MartinR Сладкое! Спасибо. – Isuru

ответ

11

Ваша первая проблема может быть решена с

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

Внутри закрытия $0 является указателем на NUL с завершающим UTF-8 представление String.

Update: Как Nate Cook сказал А теперь удален ответ, а также here, вы можете передать Swift строку в функцию принимая UnsafePointer<UInt8> непосредственно:

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

К сожалению, (насколько я знаю), в настоящее время нет решения вашей второй проблемы. SCNetworkReachabilitySetCallback ожидает указатель на функцию C как второй параметр , и в настоящее время нет способа передать функцию Swift или закрытие. Обратите внимание, что в документации для SCNetworkReachabilityCallBack отображается только Objective-C, но нет Swift.

См. Также Does Swift not work with function pointers?.


Обновление для Swift 2: Теперь можно пройти Swift закрытия к функции C принимает параметр указателя функции. Также SCNetworkReachabilityCreateWithName() не возвращает неуправляемый объект больше:

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) 

Обновление для 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) 
+0

Спасибо Мартин. Ограничения сосать :(Одна маленькая вещь. Теперь тип достижимости «Неуправляемый !». Я получаю ошибку ** «Неуправляемая » не совпадает с «SCNetworkReachability» ** при передаче ее другим функциям. Есть ли способ разрешить это? – Isuru

+0

@Isuru: я забыл takeRetainedValue(). Должно быть хорошо сейчас. –

+0

В коде Swift 3, что возвращает или выводит сообщение о том, что приложение было или не могло связаться с указанным host? – ConfusionTowers