NSData.bytes [подписка] в Swift 5 - PullRequest
       12

NSData.bytes [подписка] в Swift 5

1 голос
/ 01 октября 2019

Я пытаюсь преобразовать этот кусок кода в Swift:

NSData *testData = [@"Whatever" dataUsingEncoding:NSUTF8StringEncoding];
    void (^whatever)(NSOutputStream *) = ^(NSOutputStream *stream) {
        [stream open];
        NSRange myRange = {0};
        while (myRange.location < testData.length) {
            myRange.location += myRange.length;
            myRange.length = 4096;

            if (myRange.location + myRange.length > testData.length) {
                myRange.length = testData.length - myRange.location;
            }

            [stream write:&(testData.bytes[myRange.location])
                       maxLength:myRange.length];
        }
        [stream close];
    };

К сожалению, я действительно застрял на &(testData.bytes[myRange.location]).

Быстрые конвертеры, которые я нашел в Интернете, необработать эту часть вообще, и компилятор Swift жалуется, что:

Значение типа 'UnsafeRawPointer' не имеет индексов

Примеры с .withUnsafeBytes не показывают, какчтобы получить указатель байтов в определенном месте.

Вот быстрый код:

        let testData = "Whatever".data(using: .utf8)!
        let whatever: ((OutputStream) -> Void)? = { stream in
            stream.open()
            var myRange = NSRange()
            while myRange.location < testData.count {
                myRange.location += myRange.length
                myRange.length = 4096

                if myRange.location + myRange.length > testData.count {
                    myRange.length = testData.count - myRange.location
                }
                // the next line doesn't work
                stream.write(testData.bytes[myRange.location], maxLength: myRange.length)
            }
            stream.close()
        }

Ответы [ 2 ]

5 голосов
/ 01 октября 2019

Objective-C - это расширенный набор C, где получение адреса подписанного указателя эквивалентно добавлению смещения к указателю:

&pointer[index] == pointer + index

В вашем случае,

[stream write:&(testData.bytes[myRange.location]) maxLength:myRange.length];

эквивалентно

[stream write:testData.bytes + myRange.location maxLength:myRange.length];

Это показывает, что проблема не в подписке, а в том, как получить указатель на хранилище элементов со значением Data со смещением.

Получение указателя на хранилище элементов выполняется с использованием withUnsafeBytes() и привязкой необработанного указателя к указателю UInt8 (см. Также Запись данных в NSOutputStream в Swift 3 ). Это можно сочетать с нарезкой (testData[offset...]) для записи данных с указанным смещением:

let testData = "Whatever".data(using: .utf8)!
let whatever: ((OutputStream) -> Void)? = { stream in
    stream.open()
    var position = 0
    while position < testData.count {
        let length = min(4096, testData.count - position)
        let amount =  testData[position...].withUnsafeBytes {
            stream.write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: length)
        }
        if amount <= 0 {
            // Error or EOF
            break
        }
        position += amount
    }
    stream.close()
}

Обратите внимание, что метод write возвращает количество фактически записанных байтов (или 0 или -1). При записи чего-либо, кроме простого файла (например, сокета TCP, канала, ...), это может быть меньше значения параметра maxLength.

В качестве альтернативы вы можетеполучить указатель на хранилище элемента один раз, а затем увеличить его на количество записанных данных:

let testData = "Whatever".data(using: .utf8)!
let whatever: ((OutputStream) -> Void)? = { stream in
    stream.open()
    var length = testData.count
    testData.withUnsafeBytes {
        var ptr = $0.bindMemory(to: UInt8.self).baseAddress!
        while length > 0 {
            let amount = stream.write(ptr, maxLength: min(length, 4096))
            if amount <= 0 { break }
            ptr += amount
            length -= amount
        }
    }
    stream.close()
}
0 голосов
/ 01 октября 2019

Удалить bytes и напрямую добавить объект данных.

...