Как преобразовать Int в NSData в Swift?

В Objective-C я использую следующий код для

  1. Преобразование переменной Int в NSData, пакет байтов.

    int myScore = 0;
    NSData *packet = [NSData dataWithBytes:&myScore length:sizeof(myScore)];
    
  2. Используйте преобразованную переменную NSData в метод.

    [match sendDataToAllPlayers: 
    packet withDataMode: GKMatchSendDataUnreliable 
    error: &error];
    

Я попытался преобразовать код Objective-C в Swift:

var myScore : Int = 0

func sendDataToAllPlayers(packet: Int!,
            withDataMode mode: GKMatchSendDataMode,
            error: NSErrorPointer) -> Bool {

            return true
}

Однако я не могу преобразовать переменную Int в NSData и использовать ее как метод. Как я могу это сделать?


person Cesare    schedule 23.02.2015    source источник
comment
stackoverflow.com/a/28662828/2303865   -  person Leo Dabus    schedule 23.02.2015


Ответы (7)


С Swift 3.x до 5.0:

var myInt = 77
var myIntData = Data(bytes: &myInt, 
                     count: MemoryLayout.size(ofValue: myInt))
person Raphael    schedule 06.04.2017

В современных версиях Swift я бы сделал:

let score = 1000
let data = withUnsafeBytes(of: score) { Data($0) }
e8 03 00 00 00 00 00 00 

И преобразуйте это Data обратно в Int:

let value = data.withUnsafeBytes {
    $0.load(as: Int.self)
}

Обратите внимание: при работе с двоичными представлениями чисел, особенно при обмене с какой-либо удаленной службой/устройством, вы можете захотеть сделать порядок байтов явный, например.

let data = withUnsafeBytes(of: score.littleEndian) { Data($0) }
 e8 03 00 00 00 00 00 00 

И преобразуйте это Data обратно в Int:

let value = data.withUnsafeBytes {
    $0.load(as: Int.self).littleEndian
}

По сравнению с форматом с обратным порядком байтов, также известным как «сетевой порядок байтов»:

let data = withUnsafeBytes(of: score.bigEndian) { Data($0) }
 00 00 00 00 00 00 03 e8

И преобразуйте это Data обратно в Int:

let value = data.withUnsafeBytes {
    $0.load(as: Int.self).bigEndian
}

Излишне говорить, что если вы не хотите беспокоиться о порядке следования байтов, вы можете использовать какой-нибудь установленный стандарт, такой как JSON (или даже XML).


Для представления Swift 2 см. предыдущую версию этого ответа.

person Rob    schedule 23.02.2015
comment
IMO такой data не будет переносимым (не должен передаваться без дополнительных метаданных) между устройствами с разными порядками байтов (см. здесь). - person Drux; 25.02.2015
comment
Я действительно согласен. Я просто смоделировал свой ответ после отправка данных другим игрокам обсуждается в Руководстве по программированию Game Center, но кажется более разумным использовать архив, plist или что-то другое. прочный формат. - person Rob; 26.02.2015
comment
Вы можете использовать score.bigEndian или score.littleEndian, чтобы задать порядок байтов с определенным порядком байтов. Тогда данные будут совместимы между архитектурами, которые можно будет записывать на одной и читать на другой. - person Benjohn; 05.04.2017
comment
Я бы предложил bigEndian, поскольку обычно считается, что это сетевой порядок байтов. И это тоже, очевидно, правильный путь ;-) - person Benjohn; 05.04.2017

Вы можете преобразовать таким образом:

var myScore: NSInteger = 0
let data = NSData(bytes: &myScore, length: sizeof(NSInteger))
person David V    schedule 23.02.2015
comment
Большое спасибо! Подскажите, пожалуйста, как включить data в мой метод? Я получаю data is not a type, когда кодирую так: func sendDataToAllPlayers(data, - person Cesare; 23.02.2015
comment
Пожалуйста :) Извините, я не улавливаю вашего вопроса, что вам нужно сделать? - person David V; 23.02.2015
comment
Если вы посмотрите на второй пункт моего вопроса, там есть код функции sendDataToAllPlayers Теперь я уже перевел эту функцию, но я хотел бы включить константу data, которую вы объявили в своем ответе, в мой метод Swift. Извините за недопонимание! - person Cesare; 23.02.2015
comment
Кажется, что ответ Роба - это то, что вы ищете, это правда? я что-то пропустил? - person David V; 23.02.2015

Для любого целочисленного типа:

extension FixedWidthInteger {
    var data: Data {
        let data = withUnsafeBytes(of: self) { Data($0) }
        return data
    }
}

Пример:

let data = 1.data
person Vyacheslav    schedule 02.12.2020

Swift 5, добавьте другой вариант.

NSData старый, но все еще действующий

Запись данных:

let buffer = NSMutableData()
let size = MemoryLayout<UInt>.size
let big = 1000
let small = 10
withUnsafeBytes(of: big, { (p) in
      let bufferPointer = p.bindMemory(to: UInt.self)
      if let address = bufferPointer.baseAddress{
             buffer.append(address, length: size)
      }
})

withUnsafeBytes(of: small, { (p) in
      let bufferPointer = p.bindMemory(to: UInt.self)
      if let address = bufferPointer.baseAddress{
           buffer.append(address, length: size)
      }
 })

Чтение данных:

if let d = buffer.copy() as? Data{
     var big: UInt = 0
     var small: UInt = 0
     let size = MemoryLayout<UInt>.size
     let meta = NSData(data: data)
     meta.getBytes(&big, range: NSRange(location: 0, length: size))
     meta.getBytes(&small, range: NSRange(location: size, length: size))

     print("big:", big, "\nsmall:", small)
    //  big: 1000 
    //  small: 10 
}

Вы знаете структуру памяти, данные, помещаемые в память,

Тогда точно их выложи.

unsafe метод забавный

person dengST30    schedule 05.05.2020

Используйте этот инициализатор для преобразования каждого массива в данные

Data(element: Sequence)

пример:

let myArr     = [12,45,67,898, 100]
let myArrData = Data(myArr)
person jamal zare    schedule 17.11.2020

В зависимости от размера Int, с которым вы работаете, прямым подходом является инициализация данных с последовательностью UInt8:

let value: Int = 100
let data = Data([UInt8(value)])
// OR
let data = Data([0xFF, 0xFE])
person Brody Robertson    schedule 17.07.2020
comment
Data([UInt8(value)]) позволит вам использовать только числа › 0 и ‹ 256... - person bojan; 06.08.2020
comment
Без сомнения, именно поэтому я уточнил ответ. - person Brody Robertson; 06.08.2020