1

私は次のクラスを持っています:

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 2 および 4 を使用しており、EXC_ARM_DA_ALIGNエラーが発生しています。

入力ファイルの構造を変更できません。readオブジェクトが適切に配置されたメモリ位置から構築されるように関数を修正する方法はありますか?

4

2 に答える 2

2

はい、アライメントされていないデータの読み取りは、一部のアーキテクチャでは失敗する可能性があります。安全な方法は、バイトを (適切に配置された) 変数にコピーすることです。

したがって、最初のアイデアは、ジェネリック関数を作成することです。

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 では、さまざまな戻り値の型で関数をオーバーロードできます。したがって、実際には両方のメソッドを定義でき、コンパイラはより制限的な方を自動的に選択します。

于 2015-02-13T20:09:42.383 に答える