Преобразование метода Objective-C в Swift для NSInputStream (преобразование байтов в двойные)

У меня есть следующий код в Objective-C:

- (double)readDouble
{
    double value = 0.0;

    if ([self read:(uint8_t *)&value maxLength:8] != 8)
    {
        NSLog(@"***** Couldn't read double");
    }

    return value;
}

Оно работает. Но я не знаю, как преобразовать его в Swift. Вот мой код:

public func readDouble() -> Double {

    var value : Double = 0.0

    var num = self.read((uint8_t *)&value, maxLength:8) // got compiling error here!
    if num != 8 {

    }
}

Сообщение об ошибке:

Невозможно вызвать '&' со списком аргументов типа '($T4, maxLength: IntegerLiteralConvertible)'

Кто-нибудь может помочь? Спасибо

Данные тестирования, которые я использую (1.25):

14 AE 47 E1 7A 14 F4 3F

ОБНОВИТЬ:

Простое решение c, но как это сделать в Swift?

double d = 0;
unsigned char buf[sizeof d] = {0};

memcpy(&d, buf, sizeof d);

person Bagusflyer    schedule 15.09.2014    source источник


Ответы (3)


Это должно работать:

let num = withUnsafeMutablePointer(&value) {
    self.read(UnsafeMutablePointer($0), maxLength: sizeofValue(value))
}

Объяснение: withUnsafeMutablePointer() вызывает замыкание (блок) с единственным аргументом ($0 в сокращенной записи), установленным на адрес value.

$0 имеет тип UnsafeMutablePointer<Double>, а read() ожидает UnsafeMutablePointer<UInt8> в качестве первого аргумента, поэтому необходимо другое преобразование. Затем возвращаемое значение замыкания присваивается num.

person Martin R    schedule 15.09.2014
comment
Извини. Это не работает. У меня Невозможно вызвать 'init' со списком аргументов типа '(UnsafeMutablePointer‹T›, maxLength: IntegerLiteralConvertible)' - person Bagusflyer; 15.09.2014
comment
Хорошо, я попытаюсь. Кстати, я не тот, кто отрицает ваш ответ. Я все равно проголосую за тебя. - person Bagusflyer; 15.09.2014
comment
Но, кажется, результат не правильный. Где результат? По стоимости, я прав? - person Bagusflyer; 15.09.2014
comment
Результат: число = 8, значение = 3,31609222784626e-296. - person Bagusflyer; 15.09.2014
comment
@bagusflyer: Согласно binaryconvert.com/result_double.html?decimal=049046050053 , двоичное двойное представление 1.25 имеет вид 0x3FF40000000000000. Также обратите внимание, что iOS использует представление с прямым порядком байтов. Я протестировал код сейчас с файлом данных, содержащим 00 00 00 00 00 00 F4 3F, и результат был value = 1.25. - person Martin R; 15.09.2014
comment
@bagusflyer: я проверил код с вашими данными 14 AE 47 E1 7A 14 F4 3F, и результат был value = 1.255 - person Martin R; 15.09.2014
comment
Давайте продолжим обсуждение в чате. - person Bagusflyer; 15.09.2014

Вышеупомянутый метод не работает для меня, используя Swift 2, но я обнаружил гораздо более простой способ сделать это преобразование и наоборот:

func binarytotype <T> (value: [UInt8], _: T.Type) -> T
{
    return value.withUnsafeBufferPointer
    {
        return UnsafePointer<T>($0.baseAddress).memory
    }
}

func typetobinary <T> (var value: T) -> [UInt8]
{
    return withUnsafePointer(&value)
    {
        Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>($0), count: sizeof(T)))
    }
}

let a: Double = 0.25
let b: [UInt8] = typetobinary(a) // -> [0, 0, 0, 0, 0, 0, 208, 63]
let c = binarytotype(b, Double.self) // -> 0.25

Я протестировал его с Xcode 7.2 на игровой площадке.

person j.s.com    schedule 02.02.2016

Вот обновленная версия Swift 3 beta 6, которая отличается, спасибо Мартину.

func binarytotype <T> (_ value: [UInt8], _ : T.Type) -> T
{
    return value.withUnsafeBufferPointer
    {
        UnsafeRawPointer($0.baseAddress!).load(as: T.self)
    }
}

func typetobinary <T> (_ value: T) -> [UInt8]
{
    var v = value
    let size = MemoryLayout<T>.size
    return withUnsafePointer(to: &v)
    {
        $0.withMemoryRebound(to: UInt8.self, capacity: size)
        {
            Array(UnsafeBufferPointer(start: $0, count: size))
        }
    }    
}

let dd: Double = 1.23456             // -> 1.23456
let d = typetobinary(dd)             // -> [56, 50, 143, 252, 193, 192, 243, 63]
let i = binarytotype(d, Double.self) // -> 1.23456
person j.s.com    schedule 17.08.2016