Hatena::ブログ(Diary)

Watsonのメモ RSSフィード

2010-08-23

MacRubyのPointerクラスについて

Cocoa APIを使用していると、引数にポインタ変数を渡さなければいけないときがあります。多くはNSError* error;のような変数が必要になるケースでしょうか。

Rubyにはポインタ変数を扱うことができるクラスが存在しないため、MacRubyではPointerクラスが追加されています。

// ObjC
NSError* error;

# MacRuby
error = Pointer.new('@')
error = Pointer.new(:object)

作成したPointerインスタンスの値はerror[0]と参照することができます。Cocoa APIにもerror[0]を渡します。Cocoa APIにはerrorをそのまま渡せばMacRubyが良きに計らってくれるみたい。参考:Probing Cocoa With MacRuby

Probing Cocoa With MacRubyに書かれていますが、以下のようにPointerを使います。

$ macirb
irb(main):001:0> framework 'Cocoa'
=> true
irb(main):002:0> err = Pointer.new(:object)
=> #<Pointer:0x200c3ac80>
irb(main):003:0> string = NSString.stringWithContentsOfFile('/', encoding: NSUTF8StringEncoding, error: err)
=> nil
irb(main):004:0> puts err[0].description
Error Domain=NSCocoaErrorDomain Code=257 UserInfo=0x200c16b80 "The file “Mac OS X” couldn’t be opened because you don’t have permission to view it." Underlying Error=(Error Domain=NSPOSIXErrorDomain Code=13 "The operation couldn’t be completed. Permission denied")
=> nil


char* name[5];のようなインスタンスを作成するには、

name = Pointer.new('c', 5)
name[0] = 'a'
name[1] = 'b'
name[2] = 'c'
name[3] = 'd'
name[4] = 'e'

と、Pointer.newの第2引数にサイズを指定します。


以下の構造体 Type の調べ方を追記

Cocoaで用意されている構造体のTypeは

irb(main):015:0> NSRect.type
=> "{CGRect={CGPoint=dd}{CGSize=dd}}"

と調べることができます。NSRect *rect[2];のような変数は

rect = Pointer.new("{CGRect={CGPoint=dd}{CGSize=dd}}", 2)

# または

rect = Pointer.new(NSRect.type, 2) 

と作ることができます。

おまけ。fieldsメソッドを使うと、構造体のメンバ一覧を取得することができるようです。

irb(main):019:0> NSRect.fields
=> [:origin, :size]

参考 : Objective-CコードからCの構造体を簡単ログ出力(with MacRuby) - kyabの日記


MacRuby: The Definitive Guideの説明もあわせてご覧ください。

Pointerクラスのメソッド

  • Pointer.new(Type [, size])
  • Pointer.new_with_type(Type [, size])
    • Pointerインスタンスを作成します。Typeに指定する値は、Type Encodingsを参考にしてください。
  • Pointer.magic_cookie(Integer)
    • OpenGL に関するチケット #1112 によって追加されました。void *を受け付ける引数に対して、(void *)にキャストした即値を渡さないといけないようなケースで使うみたい。MacRuby 0.9から使えます。
  • Pointer#type
    • Typeを確認する際に使用します。
error = Pointer.new(:object)
p error.type # => "@"
  • Pointer#cast!(Type)
    • Typeを変更する際に使用します。JavaScriptを動かすときに使っているので、それを参考にしてもらえると良いかと。
  • Pointer#[nth]=value
    • nth 番目にvalueを設定します。
  • Pointer#assign(value)
    • ごめんなさい。どのように使うのかわかりません。コメントで使い方を教えてもらったので、そちらを参照してください。
  • Pointer#+ offset
  • Pointer#- offset
    • 指定したoffsetからのPointerインスタンスを返します。
    • メソッドが追加されました。MacRuby 0.8から使えます。
name = Pointer.new('c', 5)
name[0] = 10 
name[1] = 11
name[2] = 12
name[3] = 13
name[4] = 14

tmp = name + 3
2.times do |i|
  p tmp[i] # => 13, 14
end

nagachikanagachika 2010/08/23 15:12 Pointer#assign は Pointer#[]= の第一引数を 0 に固定したものです。
つまり
ptr.assign(val)

ptr[0] = val
です。

WatsonWatson 2010/08/23 15:17 おぉ、いきなりのコメントありがとうございます(^o^)/
なるほど、そのように使用するのですね〜〜

kyabkyab 2011/07/15 20:09 まとめありがとうございます。いつも参考にしてます。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/Watson/20100823/1282543331