Работа с C API из Swift
Я пытаюсь отслеживать состояние сети. Я просмотрел код FXReachability. В частности, следующий метод.
- (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. Но для типа String
существует свойство, называемое utf8
. Согласно documentation,
Вы можете получить доступ к представлению UTF-8 строки, итерации по свойству utf8. Это свойство имеет тип String.UTF8View, представляющий собой набор значений unsigned 8-bit (UInt8), по одному для каждого байта в представлении строк UTF-8:
Как я могу получить полное представление UTF8 строки вместо набора 8-битных (UInt8) значений без знака?
2. Функция обратного вызова для SCNetworkReachabilitySetCallback.
Второй параметр этой функции ожидает что-то типа SCNetworkReachabilityCallBack
. Я погрузился в исходный файл и узнал, что это на самом деле typealias
.
typealias SCNetworkReachabilityCallBack = CFunctionPointer<((SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void)>
Я определил его так.
let reachabilityCallBack: SCNetworkReachabilityCallBack = {
}()
Но я получаю ошибку. Отсутствует возврат в закрытии, который, как ожидается, вернет "SCNetworkReachabilityCallBack", когда в этом типелианах вы можете ясно видеть, что он возвращает Void
.
Это неправильный способ сделать это?
Это проблемы, с которыми я сталкиваюсь. Я был в этом часом сейчас без везения, поэтому я бы очень признателен за любую помощь.
Спасибо.
Ответы
Ответ 1
Ваша первая проблема может быть решена с помощью
let reachability = host.withCString {
SCNetworkReachabilityCreateWithName(nil, $0).takeRetainedValue()
}
Внутри замыкания $0
является указателем на UUL-8-представление NUL-конца
Строка.
Обновление: Как Nate Cook говорится в
теперь удаленный ответ, а также здесь,
вы можете передать строку Swift в функцию с UnsafePointer<UInt8>
непосредственно:
let reachability = SCNetworkReachabilityCreateWithName(nil, host).takeRetainedValue()
К сожалению, в настоящее время (насколько мне известно) нет решения вашей второй проблемы.
SCNetworkReachabilitySetCallback
ожидает, что указатель на функцию C второй
параметр, и в настоящее время нет способа передать функцию Swift или закрытие.
Обратите внимание, что документация для SCNetworkReachabilityCallBack
показывает только Objective-C, но не Swift.
См. также Не работает ли Swift с указателями функций?.
Обновление для Swift 2: Теперь можно выполнить быстрое закрытие
к функции 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)