この記事では、ポインタを迅速に操作することを検討し、なぜこれが必要なのかを推測したいと思います。
それで、最初の質問はなぜですか?
ほとんどの場合、iOS用のswiftを使用したプログラミングはポインターを使用する必要がありません;さらに、ほとんどのプログラマーはポインターを明示的に使用したことがありません。 それでも、場合によっては、このような低レベルのコードを使用すると、プログラムの速度または使用メモリ量を最適化できます。 また、このような機会は学術的な観点からも興味深いものです。
どうやって?
ポインターの一般的な作業は、メモリの割り当て、割り当てられた領域の操作、およびメモリの解放の3つの手順で構成されます。
例:
let p = UnsafeMutablePointer<Int>.alloc(1) p.initialize(20) p.destroy(1) p.dealloc(1)
迅速の観点から、ポインターは対応する型(この場合は整数)のジェネリックです
ここでは、Int型にメモリを割り当て、20の値で初期化して解放します。
ただし、この方法で1つの整数値をいじるのは特に有用ではありません。一時配列が必要な場合は別のことです。
let a = UnsafeMutablePointer<Int32>.alloc(N) memset(a, 0, sizeof(Int32) * N)
ここでは、サイズNのInt32要素の型で「a」配列にメモリを割り当て、sizeof(Int32)* Nバイトを0に設定して初期化しました。
ここで、コマンドの配列をコピーします。
var b = a
迅速な配列とは異なり、コピーされるのはデータそのものではなく、それらへのポインタです。 データは次のようにコピーできます。
let b = UnsafeMutablePointer<Int32>.alloc(N) memcpy(b, a, sizeof(Int32) * N)
このような配列の繰り返しは、非常に簡単に実行できます。
for var i = 0; i < N; i++ { a[i] = <...> }
そして、数学ポインターを使用できます。
var p = a while p < a + N { p.memory = <...> p++ }
(整数をポインターに追加し、対応する要素数を指すアドレスをシフトします)
ただし、かなり退屈な理論なので、ポインターを使用して問題を解決してみましょう。
たとえば、GIFファイルから画像のサイズを取得します。
これを行うには、実験ファイルとフォーマットヘッダーの説明が必要です。
オフセット | 長さ | 内容 |
---|---|---|
0 | 3バイト | GIF |
3 | 3バイト | 「87a」または「89a」 |
6 | 2バイト | 幅 |
8 | 2バイト | 身長 |
... | ... | ... |
まず、GIFファイルを読み取り、読み取りバイトシーケンスの先頭へのポインターを取得します。
let fileName = NSBundle.mainBundle().pathForResource("SomeGif", ofType: "gif")! let data = NSData(contentsOfFile: fileName)! guard data.length > 10 else { return } var p = UnsafeMutablePointer<Void>(data.bytes)
したがって、「p」ポインターは、GIFファイルからのデータを含むバッファーの先頭を指し、バッファーサイズが10バイトを超えていることも確認します(これは、これから読み取る量です)。
形式の説明によると、ヘッダーの最初の3バイトは文字列「GIF」である必要があります。確認するには、バッファーの最初の3バイトに基づいてSwift行を作成し、次の項目を確認します。
let str = String(bytesNoCopy: p, length: 3, encoding: NSASCIIStringEncoding, freeWhenDone: false) guard str == "GIF" else { return }
したがって、pポインターによって参照される最初の3バイトをASCII文字セットとして解釈するSwift文字列を作成します。最も注目すべきは、バッファーからのデータ自体がコピーされないことです。
さらに、チェックが成功した場合、対象の画像のサイズを読み取ります。 これを行うには、2つの16ビット整数の構造を使用します。
struct GifSize { var width: UInt16 var height: UInt16 }
形式に従って、ファイルの先頭から6バイト(以前は文字列として解釈した最初の3バイト)だけシフトし、次の4バイトを2つの16ビット数として解釈する必要があります。
p += 6 let pSize = UnsafeMutablePointer<GifSize>(p) NSLog("Gif width = \(pSize.memory.width), height = \(pSize.memory.height)")
したがって、ポインターを使用してサードパーティのライブラリなしでタイトルを読み取ることにより、GIFファイル内の画像のサイズを取得しました。
(一般的に、Swiftでの構造の同様の使用には、いくつかの落とし穴と制限がありますが、それらは別の注意に値します)