Вопрос в том, что хуже:
Для финансовых баз данных, тупики намного хуже неправильных значений. Я знаю, что это звучит в обратном направлении, но выслушайте меня. Традиционным примером транзакций БД является обновление двух строк, вычитание из одного и добавление в другое. Это неправильно.
В финансовой базе данных вы используете деловые операции. Это означает добавление одной строки в каждую учетную запись. Крайне важно, чтобы эти транзакции завершились, и строки были успешно записаны.
Неправильное получение баланса аккаунта неправильно, это то, к чему подходит согласование на конец дня. И овердрафт с учетной записи гораздо более вероятен, потому что два банкомата используются одновременно, а не из-за незафиксированного чтения из базы данных.
При этом SQL Server 2005 исправил большинство ошибок, которые сделали NOLOCK
необходимо. Поэтому, если вы не используете SQL Server 2000 или более раннюю версию, вам это не понадобится.
Дальнейшее чтение Версии уровня строк
Если вы хотите перейти через NSData
, то он будет работать следующим образом:
let bytes:[UInt8] = [0x01, 0x02]
println("bytes: \(bytes)") // bytes: [1, 2]
let data = NSData(bytes: bytes, length: 2)
print("data: \(data)") // data: <0102>
var u16 : UInt16 = 0 ; data.getBytes(&u16)
// Or:
let u16 = UnsafePointer<UInt16>(data.bytes).memory
println("u16: \(u16)") // u16: 513
Альтернативно:
let bytes:[UInt8] = [0x01, 0x02]
let u16 = UnsafePointer<UInt16>(bytes).memory
print("u16: \(u16)") // u16: 513
Оба варианта предполагают, что байты находятся в
Обновление для Swift 3 (Xcode 8):
let bytes: [UInt8] = [0x01, 0x02]
let u16 = UnsafePointer(bytes).withMemoryRebound(to: UInt16.self, capacity: 1) {
$0.pointee
}
print("u16: \(u16)") // u16: 513
Предполагая малое кодирование endian.
Чтобы преобразовать в UInt16 из [UInt8], вы можете сделать что-то вроде
var x: [UInt8] = [0x01, 0x02]
var y: UInt16 = 0
y += UInt16(x[1]) << 0o10
y += UInt16(x[0]) << 0o00
. Для преобразования в UInt32 этот шаблон распространяется на
var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
var y: UInt32 = 0
y += UInt32(x[3]) << 0o30
y += UInt32(x[2]) << 0o20
y += UInt32(x[1]) << 0o10
y += UInt32(x[0]) << 0o00
Восьмеричное представление величины сдвига дает хорошую индикацию о том, сколько полных байтов смещено (8 становится 0o10, 16 становится 0o20 и т. д.).
Это можно свести к следующему для UInt16:
var x: [UInt8] = [0x01, 0x02]
let y: UInt16 = reverse(x).reduce(UInt16(0)) {
$0 << 0o10 + UInt16($1)
}
и для UInt32:
var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
let y: UInt32 = reverse(x).reduce(UInt32(0)) {
$0 << 0o10 + UInt32($1)
}
Сокращенная версия также работает для UInt64, а также обрабатывает значения, в которых байтовая кодировка не использует все байты, такие как [0x01, 0x02, 0x03]
В Swift 3 или более поздней версии вы можете преобразовать байты [UInt8]
в Data
и получить значение UInt16
с помощью withUnsafeBytes { $0.pointee }
Swift 3 или более поздней версии
extension Data {
var uint16: UInt16 {
return withUnsafeBytes { $0.pointee }
}
}
< hr> extension Collection where Element == UInt8 {
var data: Data { return Data(self) }
}
let bytes: [UInt8] = [1, 2]
let uint16 = bytes.data.uint16
print(uint16) // 513
Как насчет
let bytes:[UInt8] = [0x01, 0x02]
let result = (UInt16(bytes[1]) << 8) + UInt16(bytes[0])
С помощью цикла это легко обобщает на большие массивы байтов и может быть обернуто в функцию для удобочитаемости:
let bytes:[UInt8] = [0x01, 0x02, 0x03, 0x04]
func bytesToUInt(byteArray: [UInt8]) -> UInt {
assert(byteArray.count <= 4)
var result: UInt = 0
for idx in 0..<(byteArray.count) {
let shiftAmount = UInt((byteArray.count) - idx - 1) * 8
result += UInt(byteArray[idx]) << shiftAmount
}
return result
}
println(bytesToUInt(bytes)) // result is 16909060
Если байты находятся в объекте NSData
, который вы можете сделать (предположим data:NSData
):
var number: UInt16 = 0
data.getBytes(&number, length: sizeof(UInt16))
Метод getBytes
записывает до двух байтов в ячейке памяти number
] (похоже на C memcpy
. Это не приведет к сбою вашего приложения, если data
не хватает байтов.
(изменить: не нужно использовать диапазон, если начинать с начала буфера)
Ответ Мартина R замечателен и хорошо обновлен для бета-версии 6. Однако, если вам нужно получить байты, которые не находятся в начале вашего буфера, предлагаемый метод withMemoryRebound
не предлагает диапазон для повторной привязки. Мое решение для этого, например. выберите второй UInt16 из массива:
var val: UInt16 = 0
let buf = UnsafeMutableBufferPointer(start: &val, count: 1)
_ = dat.copyBytes(to: buf, from: Range(2...3))