28091


NSDataを書き換えたいのですがうまくいきません。

[code]

    var baseData = NSData()
    baseData = XXXXX() ※ 別のメソッドからNSDataを取得
    
    var ptr = UnsafePointer<構造体（C言語の型にキャスト）> (baseData.bytes).memory
    withUnsafeMutablePointer(&ptr.test.info.0) { infoPtr in
        for index in 0..<infoの配列数{
            print("old\(infoPtr[index].longdata)")
            infoPtr[index].longdata = infoPtr[index].longdata.bigEndian
            print("new\(infoPtr[index].longdata)")
        }
    }
    
    var ptr2 = UnsafePointer<構造体（C言語の型にキャスト）> (baseData.bytes).memory
    withUnsafeMutablePointer(&ptr2.test.info.0) { infoPtr in
        for index in 0..<infoの配列数{
            print("check \(infoPtr[index].longdata)")※再度読みだし
        }
    }
    
[/code]

このような形で一部のデータをエンディアン変換しています。  
変換前後の値をログで見ると変わっていることを確認できるのですが  
再度読み出しても値が変わっていません。

NSDataの一部を書き換えるにはどうするのがよいのでしょうか・・・

□追記  
構造体

[code]

    typedef struct {
     short info[10];
     int infoint;
    } INFO_STR;
    
    typedef struct {
     INFO_STR test;
     int testint;
    } TEST_STR;
    
[/code]


CC BY-SA 3.0
2016-08-05T13:16:34.587
28089
2016-08-08T10:09:40.680
2016-08-05T14:33:35.727
12842
12842
question
swift
NSDataの値を変更したい。


追記していただいたコードを元に2通りの方法でコードを書いてみました。構造体の定義を見ても、`longdata`と言う名称のメンバーを持つ別の構造体は見当たらないので、そこらへんは省略しました。

以下の記述を見る前に、元の構造体が、

[code]

    struct INFO_STR {
        var info: (Int16, Int16, Int16, Int16, Int16, Int16, Int16, Int16, Int16, Int16)
        var infoint: Int32
    }
    
    struct TEST_STR {
        var test: INFO_STR
        var testint: Int32
    }
    
[/code]

…のようにSwiftにimportされているのを確認しておいてください。

* * *

(NSData以外のデータ構造を使って内容を書き換え、それを元に別のNSDataを作成する)  
こちらの方があなたの元のコードに近い書き方になります。

[code]

    let count = 10 //infoの配列数
    
    let baseData = XXXXX() //使いもしないインスタンス(`NSData()`)を作るのは避けるべき
    
    var editingData = UnsafePointer<TEST_STR>(baseData.bytes).memory //`editingData`は`baseData`の中身のコピーになる
    withUnsafeMutablePointer(&editingData.test.info) {wholeInfoPtr in //tupleを配列っぽくアクセスするときのより安全な方法
        let infoPtr = UnsafeMutablePointer<Int16>(wholeInfoPtr) //<-Int32になってました(失礼しました)
        for index in 0..<count {
            print("old\(infoPtr[index])") //提示された構造体には`longdata`なるメンバーはないので書き換え
            infoPtr[index] = infoPtr[index].bigEndian
            print("new\(infoPtr[index])")
        }
    }
    //ここまで実行が終わると`editingData`の内容が書き換わっている(`NSData`の内容ではない)
    //上の`editingData`の内容を含む`NSData`を新たに作る
    let editedData = NSData(bytes: &editingData, length: sizeof(TEST_STR))
    //新しく作った方のデータの内容を再表示
    var showingData = UnsafePointer<TEST_STR> (editedData.bytes).memory //実際にはローカル変数`showingData`にコピーされた内容を表示する
    withUnsafePointer(&showingData.test.info) {wholeInfoPtr in
        let infoPtr = UnsafePointer<Int16>(wholeInfoPtr)
        for index in 0..<count {
            print("check \(infoPtr[index])") //※再度読みだし
        }
    }
    
[/code]

* * *

(NS‌​Dataの内容をコピーしたNSMutableDataを作成し、その内容を書き換える)

[code]

    let count = 10 //infoの配列数
    
    let baseData = XXXXX()
    
    let mutableData = NSMutableData(data: baseData) //`baseData`の書き換え可能なコピーを作成する
    
    let mutablePtr = UnsafeMutablePointer<Int8>(mutableData.mutableBytes) //書き換え可能領域の先頭アドレスを取得
    //`Int8`を使っているのはバイト単位でのアドレス計算用
    
    let offsetToInfo = 0 //`TEST_STR`内での`info`の位置を手計算で算出しておく
    
    let infoPtr = UnsafeMutablePointer<Int16>(mutablePtr + offsetToInfo) //最初の`info`のアドレスを取得
    //`Int16`は構造体`INFO_STR`中の`info`のデータ型
    
    for index in 0..<count {
        print("old\(infoPtr[index])") //提示された構造体には`longdata`なるメンバーはないので書き換え
        infoPtr[index] = infoPtr[index].bigEndian
        print("new\(infoPtr[index])")
    }
    //ここまで実行が終わると`mutableData`の内容が書き換わっている
    
    //新しく作った方のデータの内容を再表示
    var showingData = UnsafePointer<TEST_STR> (mutableData.bytes).memory
    withUnsafePointer(&showingData.test.info) {wholeInfoPtr in
        let infoPtr = UnsafePointer<Int16>(wholeInfoPtr)
        for index in 0..<count {
            print("check \(infoPtr[index])") //※再度読みだし
        }
    }
    
[/code]

`NSMutableData`は`NSData`のサブクラスなので、`mutableData`を「書き換え済みの`baseData`として使用することができるようになります。

* * *

(編集メモ)  
編集前のコードも「経験上このやり方で動く」というコードだったのですが、Swiftの意味論的に  
「より確実に動く」コードに修正させていただきました。

(編集メモ2)  
いただいた例では`info`は`Int16`のtupleなのに、`Int32`としてしまっていたところが残っていました。修正しましたので、古いコードをコピーされていた場合はお気をつけください。

それも含めて何かご意見等ありましたら、コメントにてお願いします。


CC BY-SA 3.0
2016-08-05T15:24:05.403
28091
2016-08-08T10:09:40.680
2016-08-08T10:09:40.680
13972
13972
28089
answer