2015-02-13 1 views
1

У меня есть следующий класс:EXC_ARM_DA_ALIGN при чтении из NSData в Swift

class RawDataArray { 
    var data: NSData! 

    init(filePath: String) { 
     data = NSData(contentsOfFile: filePath) 
    } 

    func read<T>(offset: Int) -> T { 
     return UnsafePointer<T>(data.bytes + offset).memory 
    } 
} 

, который я использую в моем приложении IOS для чтения из двоичного файла с произвольным форматом. Например, чтобы прочитать Int по смещению 5, я использую:

let foo = rawData.read(5) as Int

Это работает в тренажере, на мой IPad Air и прошел обзор для бета-тестирования. Тем не менее, мои внешние тестеры имеют iPad 2s и 4s, и они получают ошибки EXC_ARM_DA_ALIGN.

Я не могу изменить структуру входного файла. Есть ли способ исправить функцию read, чтобы убедиться, что объекты построены из правильно выровненных мест памяти?

ответ

1

Да, чтение несвязанных данных может быть неудачным на некоторых архитектурах. Безопасный метод: копирует байты в (правильно выровненную) переменную.

Так что первая идея была бы написать обобщенную функцию:

func read<T>(offset: Int) -> T { 
    var value : T 
    memcpy(&value, data.bytes + offset, UInt(sizeof(T))) 
    return value 
} 

Однако это не компилируется,, так как переменная value должна быть инициализирована перед использованием, и не существует по умолчанию который может быть использован для инициализации полной общей переменной .

Если ограничить метод для типов, которые могут быть инициализированы с 0 то мы получим следующее:

func read<T : IntegerLiteralConvertible>(offset: Int) -> T { 
    var value : T = 0 
    memcpy(&value, data.bytes + offset, UInt(sizeof(T))) 
    return value 
} 

Это работает для всех типов точек целочисленных и плавающих.

В общем случае, можно было бы использовать эту идею из https://stackoverflow.com/a/24335355/1187415:

func read<T>(offset: Int) -> T { 
    // Allocate space: 
    let ptr = UnsafeMutablePointer<T>.alloc(1) 
    // Copy data: 
    memcpy(ptr, data.bytes + offset, UInt(sizeof(T))) 
    // Retrieve the value as a new variable: 
    var item = ptr.move() 
    // Free the allocated space 
    ptr.dealloc(1) 
    return item 
} 

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

+0

Большое спасибо за сохранение моих выходных! Я собирался начать писать ужасный код для смещения байтов и т. Д. – Eduardo

+0

@Eduardo: Добро пожаловать! –