FourSquare Venues Platform向けのC++ API

Monday, January 16th, 2012

土曜日に「Just Do(土) It. × foursquareもくもく会」があったので、飛び入りで参加。せっかくだから、C++でFoursquareのVenues Platform APIにアクセスするAPIを作成しました。無駄にするのももったいないので、需要があるのかわかりませんが、それなりの形にまとめて公開することにしました。ソースコードはCodePlexで公開しています。内部では、WinHTTPでGETリクエストを送り、JSON CPPでJSONをパースしています。

WindowsでOpenGL (GLUTを使わずGLEWで)

Thursday, January 5th, 2012

MacでOpenGLをやりたいと思っているのですが、せっかくマルチプラットフォームなOpenGLを使うならWindowsも動作確認をしておきたいということもあり、これから開発するアプリのひな形にと、Windows上で非常に単純なOpenGLアプリを作成してみました。ソースコードはこちらです。
ベースにしたのは、以前、Direct Xで作成したGame of Life 3Dです。こちらから、Direct Xに関連する部分を削除、そしてOpenGLの処理を追加しました。
WindowsでOpenGLを開発しようとして困るのが、どうやってOpenGL Contextを取得するのかという部分です。この部分は、環境依存となっており、統一した方法をOpenGL側では用意していません。そこで、多くの人が使うのがGLUTですが、これを用いると開発は簡単になるのですが、完全にブラックボックスになってしまい、プラットフォームの機能を十分に生かせません。なので、GLUTを使わず、参考にしている書籍「OpenGL 4.0 Shading Language Cookbook」にも書かれているGLEWを用いてみることとしました。また以下のOpenGL.orgの情報も参考にしました。

具体的にOpenGL Contextを作成しているのはGLContext.cpp内でです。58行目のアトリビュートにてOpenGLのバージョンを指定しています。ここでは、IntelのGPUでも動作するように2.1.0を指定しています。最新のGeforceやRadeonであれば4.2.0で動作します(手持ちのRadeon 6570とGeforce 460で確認済み)。

    static const int  att[] = {
        WGL_CONTEXT_MAJOR_VERSION_ARB,   2,
        WGL_CONTEXT_MINOR_VERSION_ARB,   1,
        WGL_CONTEXT_FLAGS_ARB,           0,
        WGL_CONTEXT_PROFILE_MASK_ARB,    WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        0,
    };

今は単純に三角形を表示しているだけですが、GLSLもきちんと使っています。Ribbonは表示していますが、終了以外は特に何もしません。内部ではTSF、Animation、Touchなどのソースも残していますが、これといって何もしていない状態です。時間があったらもう少しアプリらしくしたいと思います。

Objective-C Key-Value Coding

Sunday, January 1st, 2012

Objective-Cには「Key-Value Coding (KVC)」というものが備わっており、文字列による名前指定でプロパティの値の取得、設定といったことができるらしい。Javaだと、Java Beans + BeanUtilsを組み合わせた機能といったところでしょうか。こういった機能が言語の標準機能として備わっているというのは面白い。
参考にした資料はKey-Value Coding Programming Guideです。

Objective-CにおけるKey-Value Coding

Key-Value Codingとは

オブジェクト指向言語であるObjective-Cでは、インスタンス変数へ直接アクセスすることは許されず、以下のようにsetter/getterを定義することとなります。

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
{
    NSString *name;
}
-(NSString*)name;
-(void)setName:(NSString*)_name;
@end

@implementation MyClass
-(NSString*)name {
    return name;
}
-(void)setName:(NSString *)_name
{
    name = _name;
}
@end

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        MyClass *obj = [[MyClass alloc]init];
        [obj setName:@"James"];
        NSLog(@"%@", [obj name]);
    }
    return 0;
}

当然ながら、setter/getterを自分で実装するのではなく、プロパティとして定義することも可能です。

@interface MyClass : NSObject
@property(strong) NSString *name;
@end

@implementation MyClass
@synthesize name;
@end

どちらにしてもnameというインスタンス変数にアクセスするために、メソッドnameとsetNameを使います。
ただ、特にGUIプログラミングでは、キー名を文字列で指定して、プロパティにアクセスできると相当のコード量を減らせる場合があります。それを実現するのがKey-Value Coding(KVC)です。
具体的には、「setValue: forKey:」で値を設定し、「valueForKey:」で値を取得します。以下がコード例です。

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        MyClass *obj = [[MyClass alloc]init];
        [obj setValue:@"Richard" forKey:@"name"];
        NSLog(@"%@", [obj valueForKey:@"name"]);
    }
    return 0;
}

つまり、Objective-Cでは、プロパティもしくは決められたルールに従ったsetter/getterを作成すれば、その値を「名前の文字列(ここでは@”name”)」でアクセスすることができます。何も特別なコーディングはいりません。

Key Path

オブジェクトの中にオブジェクトがあり、そのプロパティにKVCを用いてアクセスしたい場合、Key Pathというものを使います。
例として、以下のようにParentクラスがChildクラスのインスタンスを保持していて、さらにChildクラスにnameというプロパティがある場合を考えます。

@interface Child : NSObject
@property(strong) NSString *name;
@end

@implementation Child
@synthesize name;
@end

@interface Parent : NSObject
@property(strong) Child* child;
@end

@implementation Parent
@synthesize child;
@end

この構造において、ParentクラスからいきなりChildクラスのnameプロパティへアクセスする方法を提供するのがKey Pathです。具体的には、以下のようにドットでプロパティ名を区切って指定します。

[parent setValue:@"Jeremy" forKeyPath:@"child.name"];
NSLog(@"%@", [parent valueForKeyPath:@"child.name"]);

1対多関係

先ほど説明したのは、一つの値を持つプロパティです。次は、複数の値を持つプロパティ、つまり1対多の関係を持つ場合です。

NSMutableArray型のプロパティ

当然のことながら、クラスは配列型のプロパティを持つことができ、その配列を先ほど説明したvalueForKeyメソッドで取得することができます。

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
@property(strong) NSMutableArray *languages;
-(id)init;
@end

@implementation MyClass
@synthesize languages;
-(id)init
{
    languages = [NSMutableArray arrayWithObjects: @"Objective-C", @"C++", @"Java", nil];
    return [super init];
}
@end

int main (int argc, const char * argv[])
{

    @autoreleasepool {
        MyClass *obj = [[MyClass alloc]init];
        id array = [obj valueForKey:@"languages"];
        for(int i = 0; i < [array count]; ++i) {
            NSLog(@"%@", [array objectAtIndex:i]);
        }
    }
    return 0;
}

KVCにおける一対多

先ほどの例は、プロパティがNSMutableArray型ですが、そうでない場合はどうすればよいのでしょうか。例えば、独自のデータ構造を用いている場合です。KVCでは、このような場合にも対応できるように、以下の二つのメソッドを実装していれば、KVCにおける一対多の関係と認識できるようにしています。
一対多関係の多側がいくつの要素を持つかを返す:

-(NSUInteger)countOf<Key>

指定したインデックスの要素を返す:

-(id)objectIn<Key>AtIndex:(NSUInteger)index

ちょっとイメージがつきにくいと思いますので、サンプルを以下に示します。わざと、NSMutableArrayを使わず、switch文で特定のインデックスの値を返すようにしています。

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
-(NSUInteger)countOfLanguages;
-(id)objectInLanguagesAtIndex: (NSUInteger)index;
@end

@implementation MyClass
-(NSUInteger)countOfLanguages
{
    return 3;
}
-(id)objectInLanguagesAtIndex: (NSUInteger)index
{
    switch(index) {
        case 0:
            return [NSString stringWithString: @"Objective-C"];
            break;
        case 1:
            return [NSString stringWithString: @"C++"];
            break;
        case 2:
            return [NSString stringWithString: @"Java"];
            break;
    }
    return [NSString stringWithString: @"Error"];
}
@end

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        MyClass *obj = [[MyClass alloc]init];
        id array = [obj mutableArrayValueForKey: @"languages"];
        for(int i = 0; i < [obj countOfLanguages]; ++i) {
            NSLog(@"%@", [array objectAtIndex:i]);
        }
    }
    return 0;
}

ここではlanguagesというプロパティに対して、mutableArrayValueForKeyを用いてアクセスしています。mutableArrayValueForKeyはNSMutableArrayと似たような機能を持つクラスを返します。ですが、実際にはNSMutableArrayではなく、特別なProxyオブジェクトが自動的に生成されて返されます。このProxyは、MyClassのcountOfやobjectInAtIndexにアクセスして、NSMutableArrayのように見せています。

Objective-C ARCによるメモリ管理

Saturday, December 31st, 2011

Objective-Cを勉強していて一番驚いたのがメモリ管理の仕組みです。ちょっと前までは、手動メモリ管理(MRC: Manual Reference Counting)、その後、GCがMac OS Xのみに入ったけど、最近になって新たにARC(Automatic Reference Counting)が導入されたとのこと。これからはARCが主流となるとのことで、少し調べてみました。

Appleの出している資料は、おそらくこのTransitioning to ARC Release Notesのみだと思われます。でも、どのような仕組みでARCが動作しているかの情報もなく、少しわかりにくい。

おそらく一番詳しいのはClangのAutomatic Reference Countingだと思います。これを読むと、内部でどのような動作をしているのかはわかります。ただ、じゃあ実際のコーディングはどうしたらいいのかという点は、わかりにくいです。

その点では、この記事が一番わかりやすかったです。なので、以下の内容は、これらの内容を参考にしながら書いたものです。

ARCによるメモリ管理

基本的な考え方

ARCになっても、管理の基本的な仕組みは、手動メモリ管理のときと同じです。つまり、各オブジェクトが参照カウンタ(retain counter)を持っていて、そのカウンタが0になるとオブジェクトが破棄されます。また、戻り値や一時的なオブジェクトのためにauto release poolが存在します。
ARCでは、新たに「強い参照」と「弱い参照」の概念が導入されます。強い参照は今までの参照と同じく、強い参照がある間はそのオブジェクトは破棄されません。対して、弱い参照は、弱い参照があっても、強い参照がなくなればそのオブジェクトは破棄されます。強い参照と弱い参照のどちらの参照なのかをコンパイラに教えるために、新たに__strong、__weakという修飾子が用意されます。
強い参照と弱い参照の二種類を持つ理由は「循環参照」を避けるためです。循環参照についてはこちらを参照してください。

ARCで用いる修飾子

変数のためのARC修飾子

強い参照

以下のように__strongを指定することで、その参照は強い参照と認識されるようになります。

__strong MyClass *obj = [[MyClass alloc]init];

デフォルトは強い参照となるので、通常は指定する必要はありません。このため、alloc/initで生成されたオブジェクトは、現在のスコープのライフタイムの間、維持されることとなります。「現在のスコープ」の意味するところは、多くの場合、変数が宣言された中括弧内を指します。

弱い参照

以下のように__weakを指定することで、その参照は弱い参照と認識されるようになります。

__weak MyClass *wobj = obj;

__weakが指定されたオブジェクトは、いつでも削除される可能性があります。弱い参照を用いる場合は、普通は、他の場所で強い参照が持たれているはずです(でないと、そのオブジェクトは破棄されてしまうので)。このオブジェクトが破棄された場合、この弱い参照にはnilが設定されます。これにより、破棄された後でも、nilに対するメソッド呼び出しは無視されるため、アプリケーションのクラッシュにはつながりません。

残念ながら、__weakをサポートしているのは、OS X 10.7とiOS 5からです。このため、OS X 10.6やiOS 4では使えません。代わりに__unsafe_unretainedを使うことができます。動作は、オブジェクトが破棄された場合にnilにならない以外は同じです。ただ、破棄された際にnilとならないので、破棄後のメソッド呼び出しはアプリケーションのクラッシュとなります。

プロパティのためのARC修飾子

強い参照

ARCがない頃は、以下のように記述していました。

@property(retain) NSObject *obj;

ARCでは、これを以下のように記述します。

@property(strong) NSObject *obj;

弱い参照

ARCがない頃は、以下のように記述していました。

@property(assign) NSObject *obj;

ARCでは、これを以下のように記述します。

@property(weak) NSObject *obj;

*) 一番わかりやすいのは、どこか一カ所で強い参照でそのオブジェクトを所有し、他の場所では、その弱い参照を持ち、そのオブジェクトにアクセスするという方法です。

ARCを使う場合のルール

1.alloc/init

オブジェクトを生成した後、retain/release/autorelease/retainCountを呼び出してはなりません。さらに、@selector(retain)や@selector(release)を用いたセレクタによる呼び出しもしてはなりません。

2.dealloc

deallocメソッドは自動的に生成されます。それと、直接deallocを呼び出してはなりません。ただ、インスタンス変数以外のリソースをリリースするためにカスタムdeallocを作成することは問題ありません。しかし、この際、[super dealloc]は呼び出してはなりません。これはコンパイラによって行われます。

3.プロパティの宣言

ARCがない頃は、@property宣言にassign/retain/copyパラメータを指定することで、メモリ管理の仕方をコンパイラに指示していました。しかし、ARCではこれらのパラメータは不要です。代わりに、weak/strongパラメータを指定し、コンパイラに指示します。

4.NSAutoReleasePoolの代わりに@autoreleasepoolを使う

5.C構造体内のオブジェクトポインタ

これは使ってはなりません。構造体の代わりにクラスを用いるべきです。

6.idとvoid*の間のキャスト

これはCore FoundationのCライブラリとFoundation KitのObjective-Cライブラリメソッドの間で発生します。ARCを用いる場合、CFオブジェクトがメモリ管理下から出たり、入ったりした場合に、ヒントをコンパイラに与えなければなりません。このヒントとしては、__bridgeや__bridge_retain、__bridge_transferなどです。さらに、Core FoundationオブジェクトのメモリマネージメントのためにはCFRetainとCFReleaseが必要となります。

7.その他

ゾーン(NSZone)によるメモリ管理はなくなったので、NSAllocateObjectやNSDeallocateObjectは使えない。

*) Objective-Cに閉じた世界で、あまり凝ったことをしていなければ1〜4を覚えておけばよいと思います。

関数の引数や戻り値

関数の引数

関数やインスタンスメソッドの引数として、オブジェクトを渡す場合は、普通は、呼び出し元側で強い参照を持っているので大きな問題となりません。
もし、特別な理由で、参照カウンタを+1してから関数やメソッドにオブジェクトを渡したい場合は、以下のように記述することができます。

void foo(__attribute((ns_consumed)) id x);
- (void) foo: (id) __attribute((ns_consumed)) x;

ただし、普通は、特に何もする必要はありません。(つまり、呼び出し元で、引数として渡すオブジェクトの強い参照を持ち、呼び出せばよい)

関数の戻り値

MRCの時代にautoreleaseという仕組みを用意したように、関数の戻り値をどのように返すかには工夫が必要となります。例えば、以下のようにインスタンス変数を返す場合は、参照カウンタがすでに+1されているので問題はありません。

@interface MyClass : NSObject
{
    NSString *name;
}
-(NSString*)getName;
@end

@implementation MyClass
-(NSString*)getName
{
    return name;
}
@end

でも、以下のように関数内で生成したオブジェクトを返す場合は、どう考えればよいのでしょうか。関数を抜けた際、参照カウンタが-1されてしまうと、参照カウンタが0になるのでオブジェクトが破棄されてしまいます。MRCでは参照カウンタを-1するタイミングをずらすためにautoreleaseを用いていました。ARCではどのようになるのでしょうか。

NSString* generateName()
{
    NSString *name = [NSString stringWithString:@"James"];
    return name;
}

ただ、この点について、どのように実装されているのかあまりはっきり書かれていません。Clangの資料では3.2.3 Unretained return valuesが該当箇所と思われます。以下は、該当部分の(だいたいの)訳です。

“メソッドや関数で、Objective-Cオブジェクト(つまり、参照カウンタを持つオブジェクト)を返すとなっているが、実際には、すでに参照カウンタが+1されている値を返すのではない場合は、オブジェクトが戻り側の境界において有効であることを保証しなければならない。
このような関数やメソッドから戻る場合、ARCはreturnステートメントを評価する時点でカウンタを+1する。そして、すべてのローカルスコープにおいてその状態を維持し、呼び出し境界において値が存在することを保証する。最悪のケースでは、autoreleaseが関与するかもしれない。しかし、呼び出し側は値が実際にautoreleaseプールにあるかどうかを仮定してはならない。
ARCは、呼び出し側ではこれ以上の作業は行わない。しかしながら、もしかしたら戻り値の生存期間を短くするために何かするかもしれない。”

結局はっきりしないので、以下のようなコードで実際にどこでオブジェクトが破棄されるのかを確認しました。

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
-(void)dealloc;
@end

@implementation MyClass
-(void)dealloc {
    NSLog(@"dealloc");
}
@end

MyClass* test()
{
    NSLog(@"enter test() scope");
    MyClass *obj1 = [[MyClass alloc]init];
    NSLog(@"leave test() scope");
    return obj1;
}

int main (int argc, const char * argv[])
{
    NSLog(@"enter main scope");
    @autoreleasepool {
        NSLog(@"enter autorelease scope");
        {
            NSLog(@"enter inner scope");
            MyClass *obj2 = test();
            NSLog(@"leave inner scope");
        }
        NSLog(@"leave autorelease scope");
    }
    NSLog(@"leave main scope");
    return 0;
}

考えられるのは、obj2がスコープから外れるタイミング、つまり「leave inner scope」と「leave autorelease scope」の間です。しかしながら、実際に実行してみると以下のような結果となります。

objc_unretained_return[1083:707] enter main scope
objc_unretained_return[1083:707] enter autorelease scope
objc_unretained_return[1083:707] enter inner scope
objc_unretained_return[1083:707] enter test() scope
objc_unretained_return[1083:707] leave test() scope
objc_unretained_return[1083:707] leave inner scope
objc_unretained_return[1083:707] leave autorelease scope
objc_unretained_return[1083:707] dealloc
objc_unretained_return[1083:707] leave main scope
Program ended with exit code: 0

つまり、autoreleaseの後となります。ここから推測されるのは、戻り値はautoreleaseプールに入るということになります。つまり、Clangの資料の後半の実装になっているようです。

*) ですので、@autoreleasepool {}は必ず記述する必要あります。

ブリッジキャスト

C/C++のオブジェクトとObjective-Cのオブジェクトの間の変換を行うのが、ブリッジキャストです。Objective-Cしか使わないという方は読飛ばしてかまいません。
Objective-Cのオブジェクトは、すべて参照カウンタを持っています。対して、C/C++のオブジェクトは持っていません。なので、単純にキャストすることはできません。

(__bridge T) op

(__bridge T) opは、opをT型へキャストします。もしTがObjective-Cオブジェクトポインタ型ならば、opはC/C++オブジェクトポインタ型でなければなりません。もし、TがC/C++オブジェクトポインタ型ならば、opはObjective-Cオブジェクトポインタ型でなければなりません。所有者の移動はないので、ARCは参照カウンタを+1しません。

T *obj2 = (__bridge T)obj1;

(__bridge_retained T) op

(__bridge_retained T) opは、Objective-Cオブジェクトポインタ型であるopを、C/C++オブジェクトポインタ型 Tへ変換します。ARCはopの参照カウンタを+1します。

(__bridge_transfer T) op

(__bridge_transfer T) opは、C/C++オブジェクトポインタ型であるopを、Objective-Cオブジェクトポインタ型 Tへ変換します。ARCはopの参照カウンタを-1します。

通常、(__bridge_retained T) opと(__bridge_transfer T) opは対で使います。__bridge_retainedで、C/C++へポインタを渡し、__bridge_transferで結果のポインタを戻すことになります。

補足: C++プログラマにとってのARC

C++ 11で正式に採択されたstd::shared_ptr<>が、Objective-Cでの強い参照(__strong)となり、std::weak_ptr<>がObjective-Cでの弱い参照(__weak)となります。関数の戻り値については、呼び出し元で受け取った際に+1されるので、ややこしい仕組みは持っていない(はず)です。Clangの資料の前半に近い実装なのだと思います。

補足: WindowsプログラマにとってのARC

MRCがCOM(AddRef/Release)、ARCがATL(CComPtr)と思ってください。

Mac Mini

Saturday, December 31st, 2011

初めてMacを購入!

DirectWrite: Ellipsis trimming sign

Tuesday, January 18th, 2011

I tested to add a ellipsis trimming sign to the text with DirectWrite. The key point is that I need to invoke CreateEllipsisTrimmingSign().

IDWriteInlineObject *inlineObject = nullptr;
m_pDWriteFactory->CreateEllipsisTrimmingSign(
  textLayout,
  &inlineObject);
DWRITE_TRIMMING trimming =
  {DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0};
textLayout->SetTrimming(&trimming, inlineObject);
sample 1
std::wstring text(L"aaaaaaaaaaaa");
m_pDWriteFactory->CreateTextLayout(
  text.c_str(),
  text.length(),
  textFormat,
  160.0f, 80.0f,
  &textLayout);

sample 2
std::wstring text(
  L"aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa");
...

sample 3
std::wstring text(
  L"aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa");
...
DWRITE_TRIMMING trimming =
  {DWRITE_TRIMMING_GRANULARITY_WORD, 0, 0};
textLayout->SetTrimming(&trimming, inlineObject);

DirectWrite: Metrics

Tuesday, January 18th, 2011

I investigated what metrics I can get from DirectWrite text layout (IDWriteTextLayout).

IDWriteTextLayout::GetMaxWidth(), GetMaxHeight()

It seems that GetMaxWidth() and GetMaxHeight() simply return the layout width and height which are specified at IDWriteFactory::CreateTextLayout method().

IDWriteTextLayout::DetermineMinWidth(FLOAT)

DetermineMinWidth() returns the maximum width of the word in the text. If the layout width is smaller than this width, the word in the text is broken.

example 1:
std::wstring text(L"Aa Bbbbb");
m_pDWriteFactory->CreateTextLayout(
  text.c_str(),
  text.length(),
  textFormat,
  120.0f, 30.0f,
  &textLayout);
FLOAT width;
textLayout->DetermineMinWidth(&width);

example 2:
std::wstring text(L"Aaaaaa Bbb Cccc");
...

DWRITE_TEXT_METRICS layoutWidth/layoutHeight

layoutWidth and layoutHeight of a DWRITE_TEXT_METRICS structure are same as the layout width and height which are specified at IDWriteFactory::CreateTextLayout method().

DWRITE_TEXT_METRICS width/height

DWRITE_TEXT_METRICS.width indicates the width of the formatted text, while ignoring trailing whitespace at the end of each line.

DWRITE_TEXT_METRICS.height indicates the height of the formatted text.

example 1:
std::wstring text(L"Abc");
m_pDWriteFactory->CreateTextLayout(
  text.c_str(),
  text.length(),
  textFormat,
  120.0f, 30.0f,
  &textLayout);
DWRITE_TEXT_METRICS textMetrics;
textLayout->GetMetrics(&textMetrics);

example 2:
std::wstring text(L"  Abc  ");
...

example 3:
std::wstring text(L"Abc Def");
...

DWRITE_TEXT_METRICS widthIncludingTrailingWhitespace

DWRITE_TEXT_METRICS.widthIncludingTrailingWhitespace indicates the width of the formatted text, taking into account the trailing whitespace at the end of each line.

example 1:
std::wstring text(L"  Abc  ");