2011-05-03

いまどきの2Dゲームエンジン

スクリプト言語でiPhoneやAndroid用ゲームを作れる2Dゲームエンジンをまとめてみる試み。


name Corona moai Imapct Kobold2D
link
link
link
link/iOSImpact
link
desc
Corona is the world’s most advanced mobile development platform.
The mobile platform for pro game developers.
Impact is a JavaScript Game Engine that allows you to develop HTML5 Games in no time.
Kobold2D™ is the expert's choice for Cocos2D game development.
license proprietary OpenSource
(CPAL)
proprietary OpenSource
(MIT License)
language Lua Lua Javascript Lua
native ?(C++) C++ ?(Objective-C) Objective-C
iOS available available available available
Android available available not yet -
price $199/year Free $99 Free
release released private beta beta 2011 summer

2011-03-30

MacVim-KaoriYa 20110330

MacVim-KaoriYa 20110330版をリリースしました。

今回はSparkleによる自動更新を設定していません。(2011/04/01 Sparkle情報を更新しました)

http://code.google.com/p/macvim-kaoriya/

http://macvim-kaoriya.googlecode.com/files/macvim-kaoriya-20110330.dmg

Xcode 4でビルドしています。

Mac OS X 10.5 Leopardを使用されている方、Intel、PowerPC 問わず、動作確認にご協力いただけますと幸いです。

Vim 7.3.146、MacVim Snapshot 57、香り屋パッチ 20110323ベースです。


(2011/04/01 追記)
実験的レンダラを使用していない場合、半透明設定(set transparency)が効かなくなります。半透明設定を使用している場合は、「環境設定」「詳細」の「実験的レンダラを使用する」「インラインインプットメソッドを使用する」の両方をチェックしてみてくださいませ。

2011-03-25

Xcode4でPowerPC


$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gcc/darwin/ppc /Developer/usr/libexec/gcc/darwin
$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gcc/darwin/ppc /usr/libexec/gcc/darwin


Xcode 4.0.1でも治ってませんでした。バグレポート忘れてたんですが。

これやっとくと、MacPortsでLeopard用のuniversal buildも可能になります。


$ sudo port install ncurses +universal macosx_deployment_target=10.5 configure.cc=/usr/bin/gcc-4.2 configure.cxx=/usr/bin/g++-4.2

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その8



本屋にも並んでます『iOS 4プログラミングブック』。

補遺その8、というか、間違いのお知らせです。ごめんなさい。

iOS 4プログラミングブック 第5章
190ページ 図5-2-5「ヒープからヒープへのコピー」の先頭行に間違いがあります。

(誤) block_t block3_on_heap = Block_copy(block_on_stack);
(正) block_t block3_on_heap = Block_copy(block_on_heap);


@eyesrobe様に発見していただきました。ありがとうございます。

2011-03-03

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その7



そろそろ浸透して話題にも上がらなくなってきた(?)『iOS 4プログラミングブック』。

補遺その7では、BlocksのObjective-C支援機能に切り込んでみます。

191ページに書いてあるとおり、Objective-Cのオブジェクトは、Block_copy時に自動的にretainされます。


NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSString *string = [NSString stringWithFormat:@"score = %d", score];

void (^block)() = Block_copy(^{

NSLog(@"%@", string);

});

[pool drain];

/* stringはblockからretainされてるから、まだ生きてる */



これどういう仕組みなんでしょう?


Objective-Cのオブジェクトは、みなNSObjectの子供。

NSObjectは、C言語としては、__attribute__((NSObject))アトリビュートの付いた変数。


てことで、Block_copy時に__attribute__((NSObject))のついた変数をretainして、Block_release時にreleaseするコードを、コンパイラは簡単に生成できるわけですね。


http://clang.llvm.org/docs/Block-ABI-Apple.txt
2.2.1 Importing __attribute__((NSObject)) variables.



しかし、この自動retainする機能。便利なのはいいのですが、実は気づかないうちに、循環参照してdeallocされない状況に陥ることもある諸刃の剣。

Blockが、Blockをretainしているクラスのselfを自動retainしちゃう、という落とし穴。

詳しくは『iOS 4プログラミングブック』の193ページに!

2011-02-08

OpenGL ES 開発リソースまとめ

GPU作ってるとこのOpenGL ES 1.1/2.0開発リソースが、実は大変充実しています。まとめてみました。

■POWERVR Insider http://www.imgtec.com/powervr/insider/powervr-insider.asp

□主な使用機種: iPhone 3G(MBX),DROID(SGX530),iPhone 4/iPad(SGX535),Nexus S/Galaxy S(SGX540),NGP(SGX543),...

・POWERVR Insider SDK。COLLADAから変換したPOD形式を使って3Dモデルの描画、アニメーション可能。ソースコードのライセンスは非常にゆるい(forumのSDK Code Licenseスレッド参照)。

・PowerVR圧縮テクスチャPVR用コンバータ PVRTexToolなどのツールも充実。

■ADRENO GRAPHICS http://developer.qualcomm.com/dev/gpu

□主な使用機種: Xperia,Nexus One,Desire,IS03,Regza,Windows Phone 7...

・Adreno™ Profilerが凄い。rootとったNexus OneなどをUSBケーブルで繋ぐだけで、リアルタイムにGPUの負荷やテクスチャ、描画結果を取得可能。

・Adreno向けに最適化されたOpenGL ES 2.0 shader source codeあり。でもOpenGL ES 2.0であればどこででも。

■TEGRA DEVELOPER ZONE http://tegradeveloper.nvidia.com/tegra/

□主な使用機種: dynabook AZ,各種タブレット,...

・Android NDK用のサンプルコードはApache License 2.0。JNI経由で音を鳴らす方法なども含んでいるので、NDKで開発する場合は必見。

・EclipseでNDKをデバッグするためのNVIDIA Debug Manager for debugging Android NDK applications in Eclipse とかあったりする。

■Mali Developer Center http://www.malideveloper.com/index.php

□主な使用機種: コンシューマ製品があるかどうか不明

・Mali GPU Shader Development Studio。IDE的に結果をみながらshader開発が可能。


また各サイトでWindowsやLinux用のOpenGL ES 1.1/2.0 emulator libraryが配布されてますので、iPhoneやAndroid向けに作ったOpenGL ES 1.1/2.0用のソースコードを、WindowsやLinux用にビルドして実行することが可能です。

各GPUごとの開発リソースは大変特色が出ているのですが、OpenGL ES 1.1/2.0経由で使うことになりますので、profilerなど専用なもの以外は、どれででも使えてしまいます。便利に使っちゃいましょう。

2011-02-03

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その6



楽天BOOKSで一時売り切れになるも、再度入荷中の『iOS 4プログラミングブック』。Amazonでは相変わらず在庫切れ...

補遺その6では、ちょっと趣向を変えてサンプルコードを説明してみます。

第5章マルチスレッドのサンプルコードは、実はTumblr Image Viewerになっていたり、cocos2d for iPhoneを使っていたりする、実戦さながらのサンプルコードとなっております。

今回はcocos2dでの非同期テクスチャ読み込みについて掘り下げてみます。


cocos2dの非同期テクスチャ読み込みAPIは、読み込み終了時にtargetのselectorを呼ぶコードになっています。これBlocksだと楽になるような気がしませんか? Blockを受け取って呼び出すClassを作ってみます。

■TextureCallback.h

/*
* 「5-1 Blocksの概要」(178ページ)
* TextureCallbackクラスにより、
* cocos2dのイメージ非同期読み込み終了コールバックを、
* Blocksに結びつけることにより、より簡単にコールバックを記述できます。
*/

#import "cocos2d.h"

/*
* 「5-2-2 値としてのBlock」(184ページ)
* typedefを使用したBlocksの宣言。
*/
typedef void (^textureCallbackBlock_t)(CCTexture2D *texture);

@interface TextureCallback : NSObject
{
textureCallbackBlock_t block_;
}

/*
* イメージ非同期読み込み終了コールバックで実行されるBlockを指定。
*/
+ (id)callbackWithBlock:(textureCallbackBlock_t)block;
- (id)initWithBlock:(textureCallbackBlock_t)block;
- (void)callback:(CCTexture2D *)texture;

@end


■TextureCallback.m

#import "TextureCallback.h"

@implementation TextureCallback

+ (id)callbackWithBlock:(textureCallbackBlock_t)block
{
return [[[self alloc] initWithBlock:block] autorelease];
}

- (id)initWithBlock:(textureCallbackBlock_t)block
{
if ((self=[super init])) {

/*
* 「5-2-4 Block_copy」(188ページ)
* 渡されたBlockをretainするためにObjective-Cのcopyを使用。
*/
block_ = [block copy];
}

return self;
}

- (void)dealloc
{

/*
* 「5-2-4 Block_copy」(188ページ)
* retainしたBlockをreleaseするためにObjective-Cのreleaseを使用。
*/
[block_ release];
[super dealloc];
}

- (void)callback:(CCTexture2D *)texture
{
/*
* 「5-2-2 値としてのBlock」(184ページ)
* cocos2dのイメージ非同期読み込み終了時Blockを実行。
*/
block_(texture);
}

@end


て感じで。使うときは


#import "TextureCallback.h"

/*
* 非同期イメージ読み込み終了時に
* 実行されるBlockを指定。
*/
TextureCallback *textureCallback =
[TextureCallback callbackWithBlock:
^(CCTexture2D *texture) {

[self addTexture:texture index:index];

}];

/*
* cocos2dの非同期イメージ読み込み
* (要メインスレッド(Main Queue))
*/
[[CCTextureCache sharedTextureCache]
addImageAsync:path target:textureCallback
selector:@selector(callback:)];



さらに、


+ (id)addImageAsyncWithBlock:(NSString *)path block:(textureCallbackBlock_t)block
{
id textureCallback = [[[self alloc] initWithBlock:block] autorelease];

[[CCTextureCache sharedTextureCache]
addImageAsync:path target:textureCallback
selector:@selector(callback:)];

return textureCallback;
}


こんな感じのクラスメソッドにすれば、


#import "TextureCallback.h"

/*
* 非同期イメージ読み込み終了時に
* 実行されるBlockを指定。
*/
[TextureCallback addImageAsyncWithBlock:path block:^(CCTexture2D *texture) {

[self addTexture:texture index:index];

}];


あらすっきり。


CCTextureCacheは渡ってきたtextureCallbackをコールバック終了までretainするので、コールバック終了までちゃんと生存。textureCallbackで持つことになるblockもtextureCallback生存中はretain(copy)されるので、メモリ管理も簡単、安心。


iOS 4プログラミングブックのサンプルコードは、http://www.impressjapan.jp/books/2976のダウンロードよりどうぞー

2011-01-31

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 まとめ



2011年1月27日発売の『iOS 4プログラミングブック』。このうち

■第5章 マルチスレッド - Blocks、Grand Central Dispatch の詳解。57ページ。
■第10章 ユニバーサル対応 - ユニバーサルアプリケーションについて。15ページ。

を書かせていただきました。

この「第5章 マルチスレッド」にて、ちょっとAdvanced過ぎるかも、と思った内容を補遺として連載しています。


__block修飾子」について
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その1
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その2
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その3
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その4
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その5



サンプルコード」について
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その6



Blocks」について
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その7



本の間違いについて
『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その8




『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その5

そろそろ皆様のお手元にもあるのではないかと思ったりしております。『iOS 4プログラミングブック』。

__block変数の書き換えは、スレッドセーフではない

さて、マルチスレッド下で安全に__block変数を書き換える方法とは。

そもそもマルチスレッドにするためにGCDのGlobal Queueを使ってるわけですから、やはりここはDispatch Semaphoreを使っておきましょう。詳しくはワシの226ページに書いてあーる。


#import <dispatch/dispatch.h>
#import <stdio.h>

int main()
{
__block int total = 0;

dispatch_semaphore_t sema = dispatch_semaphore_create(1);
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10000, queue, ^(size_t index) {

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

++total;

dispatch_semaphore_signal(sema);

});
dispatch_release(sema);

printf("total=%d\n", total);

return 0;
}


ふつうにセマフォです。


あと、今回の場合、Atomic operationsが使えます。

http://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/atomic.3.html


#import <libkern/OSAtomic.h>



dispatch_apply(10000, queue, ^(size_t index) {

OSAtomicIncrement32(&total);

});


Barrierあり/なしの使い分けは、http://stackoverflow.com/questions/2436513/macosx-osatomic-vs-osatomicbarrierにありました。


もしくはGCC組み込みAtomic関数(http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html)を使うのも手です。


dispatch_apply(10000, queue, ^(size_t index) {

__sync_fetch_and_add(&total, 1);

});


clangでも使えます。Mac OS X、iOS以外の環境でも使える点がメリットでしょうか。また上記のとおり、OSAtomicに対して若干汎用的すぎるところがデメリットと言えるかと(++がないとか)。移植性を取るかどうか、てことですね。GCC拡張使って移植性どうこう言うのもあれだとは思いますが。

てことで、__block修飾子に関しては、以上で終りです。補遺はまだ続くかもしれません。

2011-01-28

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その4

そろそろ皆様のお手元にもあるのではないかと思ったりする『iOS 4プログラミングブック』。

「しかし、第5章『マルチスレッド』の補遺の割に、ちっともマルチスレッドじゃない」

とお嘆きの読者様。朗報です。やっとマルチスレッドの話です。


__block変数への書き込みってスレッドセーフ??


GCDのdispatch_applyで、Global QueueにBlock突っ込むと、それはもう簡単に複数スレッドから同時に__block変数を書き換えることができます。


... あ、もしかして、GCDことGrand Central Dispatch、よくご存知でなかったりしますでしょうか? そういう話でしたら、それはもう詳しく説明している本がありますので、この場を借りてご紹介できればな、と思います。



iOS 4プログラミングブック
■5-3 Grand Central Dispatchの概要
■5-4 Grand Central Dispatchの解説



はい、宣伝させていただいてありがとうございます。dispatch_applyでガンガン__blockを書き換えるソースを書いてみます。


#import <dispatch/dispatch.h>
#import <stdio.h>

int main()
{
__block int total = 0;

dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10000, queue, ^(size_t index) {

++total;

});

printf("total=%d\n", total);

return 0;
}


実行すれば


total=10000


と出るはずです。実行してみましょう!


total=6749


あれ。あ、ちなみにCore 2 DuoなMacBook Proで実行してますよ。もう一度。


total=10000


期待通り。念のためもう一回。


total=8664


うーん。ということで、すでにお気づきのことと思いますが、

__block変数はスレッドセーフではありません


その1から読んでくださっている読者の方には当然の結果かとおもいます。clang -rewrite-objcで見たとおり、++(total.__forwarding->total);になってるだけですから、スレッドセーフなわけがないのです。

マルチスレッド下で、__block変数を安全に更新する方法とははたして!? つづきます。

2011-01-27

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その3

いよいよ本日、2011年1月27日発売!の『iOS 4プログラミングブック』。

その1その2と「__block修飾子」について深追いしてきましたが、まだ潜ってみます。ぶくぶくぶく。


潜る前に、まずは地図を見ておきましょう。

179ページにあるとおり、Blocksのことが知りたかったらLLVMのドキュメントを参照します。


http://clang.llvm.org/docs/BlockLanguageSpec.txt
http://clang.llvm.org/docs/Block-ABI-Apple.txt


... しかしまぁ、言うは易く行うは難し。英語読むくらいならソースコード読むほうが楽ですね。地図なしで。


てことで、ソースを読んでみます。ぶくぶくぶく。

Block_copyとかBlock_releaseとかは、C言語のランタイムライブラリの一部としてLLVMのソースツリーに入ってます。

https://llvm.org/svn/llvm-project/compiler-rt/trunk/BlocksRuntime/Block_private.h
https://llvm.org/svn/llvm-project/compiler-rt/trunk/BlocksRuntime/runtime.c

このへん。

その2で出てきたflags: 0x1000002のbit定義がありますね。


enum {
BLOCK_REFCOUNT_MASK = (0xffff),
BLOCK_NEEDS_FREE = (1 << 24),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};


BLOCK_REFCOUNT_MASK = 0xffff... 65536回Block_copyするとやばそうですね!


それはさておきBlock_copyすると、__block変数は_Block_byref_assign_copy()でcopyされます。


/*
* Runtime entry points for maintaining the sharing knowledge of byref data blocks.
*
* A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
* Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
* We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
* Otherwise we need to copy it and update the stack forwarding pointer
* XXX We need to account for weak/nonretained read-write barriers.
*/

static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {



forwardingポインタに代入しているところを見ると


copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
src->forwarding = copy; // patch stack to point to heap copy


heap上構造体のforwardingも、stack上構造体のforwardingも、heap上の構造体を示すように書き換えられてます。安心して__block変数を操作できますね。


その2で使った秘密の_Block_byref_dump()もありますよ。


ちなみに、Mac OS X 10.5/iOS 3.1.3以前でもBlocksを使えるようにするplblocksてのがあります。

http://code.google.com/p/plblocks/source/browse/Runtime/trunk/Source/Runtime/Block.m

たとえばiOS SDK 4.2に入っているtoolchain(gcc, llvm-gcc, clang)は、Block構文をコンパイルすることが可能です。ということで実は、Deployment Targetを3.1.3にしても(Deployment Targetについては、iOS 4プログラミングブック 第10章ユニバーサル対応で詳しく説明してますよ!)、stack上でだけならBlocksを使うことができます。ただしBlocks用ランタイムがないため、Block_copy/Block_releaseなどはできません。そこで、plblocks runtimeのヘッダをインクルードして、plblocks runtimeのソースとともにコンパイルすると、plblocksのBlock_copy/Block_release実装を使えるようになるわけです。

ついでにlibdispatchを使えば、iOS3.1.3とかでもGrand Central Dispatchまで使えるわけですが、それはまた別の講釈で...

__block修飾子については語りつくした感がありますが、まだつづくよ

2011-01-26

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その2

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その2

2011年1月27日発売でも、すでに書店に並びつつある『iOS 4プログラミングブック』。

今回も引き続き第5章マルチスレッドの補遺として、「__block修飾子」を深追いしてみます。

その1で書いたとおり、__block変数の実態は「total.__forwarding->total」て感じです。Block生成直後はstackに居るので、この__forwardingポインタは自分が含まれる構造体を示し、Block_copyでstackからheapに移動されると(189ページ参照)、__forwardingポインタが移動後のアドレスを示すわけですね。「total.__forwarding->total」は、stackにあるか、heapにあるか、気にせずにアクセスできるわけです。


確かめてみましょう!


#import <Foundation/Foundation.h>
#import <stdio.h>

extern const char *_Block_byref_dump(void *);

void dump(int line, int *p)
{
p -= 4;
printf("\ndump line:%d\n", line);
puts(_Block_byref_dump(p));
}

int *test()
{
__block int total = 11;

dump(__LINE__, &total);

void (^block_on_stack)() = ^{

++total;

dump(__LINE__, &total);
};

block_on_stack();

printf("\n___ Block_copy ___\n");
void (^block_on_heap)() = Block_copy(block_on_stack);

dump(__LINE__, &total);

block_on_stack();

block_on_heap();

printf("\n___ Block_release ___\n");
Block_release(block_on_heap);

dump(__LINE__, &total);

block_on_stack();

return &total;
}

int main()
{
dump(__LINE__, test());
}


__block変数をダンプするための秘密の関数 _Block_byref_dump を使って、それぞれの状況で__block変数の状態を表示してみます。このソースコードに埋めてみましょう。


int *test()
{
__block int total = 11;

dump(__LINE__, &total);

dump line:17
byref data block 0xbffffa70 contents:
forwarding: 0xbffffa70 ← stackに生成されてる
flags: 0x0
size: 20


void (^block_on_stack)() = ^{

++total;

dump(__LINE__, &total);
};

block_on_stack();

dump line:23
byref data block 0xbffffa70 contents:
forwarding: 0xbffffa70 ← stack上のBlockからstack上の__block変数を使用
flags: 0x0
size: 20


printf("\n___ Block_copy ___\n");
void (^block_on_heap)() = Block_copy(block_on_stack);

dump(__LINE__, &total);

dump line:31
byref data block 0x100150 contents:
forwarding: 0x100150 ← heapにコピーされた!
flags: 0x1000002 ← 要Block_releaseフラグと、参照カウンタ(2)
size: 20


block_on_stack();

dump line:23
byref data block 0x100150 contents:
forwarding: 0x100150 ← stack上のBlockからheap上の__block変数を参照している
flags: 0x1000002
size: 20


block_on_heap();

dump line:23
byref data block 0x100150 contents:
forwarding: 0x100150 ← heap上のBlockからheap上の__block変数を使用している
flags: 0x1000002
size: 20



printf("\n___ Block_release ___\n");
Block_release(block_on_heap);

dump(__LINE__, &total);

dump line:40
byref data block 0x100150 contents:
forwarding: 0x100150
flags: 0x1000001 ← Block_releaseしたので参照カウンタが減少(2→1)
size: 20


block_on_stack();

dump line:23
byref data block 0x100150 contents:
forwarding: 0x100150 ← stack上のBlockからheap上の__block変数を使用。まだ参照カウンタが1なのでheap上に残存
flags: 0x1000001
size: 20


return &total;
}

int main()
{
dump(__LINE__, test());

dump line:49
byref data block 0x100150 contents:
forwarding: 0x100150
flags: 0x1000000 ← 参照カウンタが0なのでheap上に残ってないはず!
size: 20

}

(Mac OS X 10.6、clang -m32で確認)


てことで、Block_copy使うと、本当にstackからheapに移動してることがわかりました。

ついでに、Block_releaseしても、heapからstackに戻すわけじゃなさそうなこともわかりました。

あ、dump関数が、「total.__forwarding->total」からのアクセスなので、Block_copy以降全部heapに存在しているように見えますが、stack上のtotal.__forwardingがちゃんとheap上のものをさしているので、stack上のtotal構造体を触っても平気です。

もはや誰得の情報なのか混迷を極めて来ましたが、つづきます。

2011-01-25

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その1

そろそろ書店に並びつつある、かもしれない、『iOS 4プログラミングブック』。

「第5章 マルチスレッド」にて、ちょっとAdvanced過ぎるかも、と思った内容を補遺として連載してっちゃいますよ。



というわけで今回は、本当に187ページで説明している「__block修飾子」について、もうちょっと掘り下げてみます。

たとえば、「__block修飾子」を付けたint型のauto変数を用意してみましょう。


int main()
{
__block int total = 11;

++total;

return total;
}


「__block」付いてる以外は、ごく普通のコードです。

しかし、コレ実際何がどうなるんでしょうか。


実は、clangを使うと一瞬でわかります。


$ clang -rewrite-objc test.m


これでObjective-Cのソースコードを、おなじみのC++のソースコードに変換することが可能なのです。

あ、C++になじみがない方もご安心を。--rewrite-objcで生成されるC++ソースコードは、ほぼC言語です(ほぼC言語なのにC++として生成されるのか、それは謎です)。


生成されたC++ソースコードを見てみると。


(抜粋)
#define __block

struct __Block_byref_total_0 {
void *__isa;
__Block_byref_total_0 *__forwarding;
int __flags;
int __size;
int total;
};

int main()
{
__block struct __Block_byref_total_0 total = {
(void*)0,
(struct __Block_byref_total_0 *)&total,
0,
sizeof(struct __Block_byref_total_0),
11
};

++(total.__forwarding->total);

return (total.__forwarding->total);
}


int型だったtotalが、なにやら複雑な構造体になっていることがわかります。そして元々のint totalは、構造体のメンバーとして収納されています。

なぜこのような構造体が必要なのか。それはiOS 4プログラミングブック 189ページで説明しているように、Block_copyによって__block変数がstackからheapに移動されてもへいちゃら! と言えるようになっているわけです。

以上、何気なく付けた__block修飾子が実はこんな構造体になってました、というお話でした。

その2に続きます。

2011-01-24

iOS 4プログラミングブック サンプルコード



今週には本屋に並ぶ『iOS 4プログラミングブック』ですが、本の内容をよりよく理解できるように、サンプルコードも準備させていただいています。

http://www.impressjapan.jp/books/2976

発売日の2011年1月27日には、上記URLよりサンプルコードにアクセスできると思います。
(2011/1/24追記: すでにサンプルコードにアクセスできます!)


私が担当した2つの章

■第5章 マルチスレッド
■第10章 ユニバーサル対応

でも、それぞれ1つづつサンプルコードを用意してます。

第5章 マルチスレッド用のサンプルコードでは、Blocks、Grand Central Dispatchをそりゃもうふんだんに使用しました。まさに実戦サンプルアプリケーションではないかと思います。しかも趣味丸出しの、まさかのcocos2d使用!です。

ソースコードは、こんな感じです。


/*
* 「5-4-2 Dispatch Queue」(213ページ)
* 各記事のフォトイメージを取得するための非同期HTTP通信は、
* メインスレッド(Main Queue)で実行される必要がある。
*/
dispatch_async(mainQueue, ^{

/*
* 非同期HTTP通信(要メインスレッド(Main Queue))
*/
[AsyncURLConnection request:imgUrl
completeBlock:^(NSData *data) {

/*
* 「5-4-2 Dispatch Queue」(213ページ)
* 各フォトイメージに対する処理は
* メインスレッド(Main Queue)で実行される必要はないので
* Global Queueで実行。
*/
dispatch_async(globalQueue, ^{

/*
* ファイル書き出しを、メインスレッドで行うと
* UI更新やイベント処理が遅延するため、
* メインスレッド以外で実行させる必要がある。
*/


iOS 4プログラミングブック』は、今週、2011年1月27日発売です。是非お手にとってみてくださいませ。

2011-01-14

Objective-Cのautorelease

Objective-Cのautoreleaseで、実際に何が起こるのか。オープンソースのCocoa実装GNUstepのソースコードで追いかけてみました。

http://togetter.com/li/88945 「autoreleaseのひみつ」

Cocoa全クラスの親クラス NSObjectにautoreleaseメソッドがあり、このautoreleaseメソッドは、NSAutoreleasePoolクラスのクラスメソッドaddObject:メソッドを呼ぶだけです。


[hoge autorelease];
/* [NSAutoreleasePool addObject:hoge]; と同じ */


NSAutoreleasePool addObject:は、そのスレッドのカレントプールにオブジェクトを追加します。メインスレッドの場合、通常NSRunLoopのループ先頭で確保されたプールになります。

NSRunLoopのループ終わりで、確保されていたプールが解放され、そのプールに入っているオブジェクト全てにreleaseが送られます。

図解すると次の通り。


(※ pool = [[NSAutoreleasePool alloc] init]; ですね)

NSAutoreleasePoolをalloc,initすると、そのプールがカレントプールになります。以下のようなスタックになってます。


(※ こちらもpool* = [[NSAutoreleasePool alloc] init]; ですね)

クラスメソッドを呼びまくったり([NSString stringほげ]とか)、autoreleaseを呼びまくるようなシチュエーション、たとえば、たくさん画像を読み込む場合。ファイルを読み込んだNSDataオブジェクト。それから作ったUIImageオブジェクト。サイズを変更したりしてまたUIImageオブジェクト。なんて時にautoreleaseしただけでreleaseされてないオブジェクトが大量に残ったりします。


for() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

/* 画像読み込み処理 */;

[pool drain];
}


とすれば、こまめにreleaseすることができます。Mac OS Xでガベージコレクションいかしたプログラミングする時に役立つように、drainを使っておきましょう。GCされます。


メモリ管理全般の話は、Memory Management in Objective-Cがわかりやすいかと思います。iDeveloper TVのフリーセッションビデオです。Objective-Cのallocの前に、そもそもC言語のmallocで何が起きるのか、から入っています。


あ、そういえば、iPhone開発本「iOS 4プログラミングブック」(2011年1月27日発売) 344ページ中70ページくらい書いたりしています。BlocksとGrand Central Dispatchについて、本当に詳しく書きましたので、よろしければ是非。

2011-01-13

iPhoneアプリ開発講座

マディソン・エリア工芸学校(Madison Area Technical College)のiPhone開発講座がとてもとてもとても充実しています。

1項目3時間(実際の授業では1時間×3コマみたいです)に及ぶビデオがなんと14本(Springの14は3分割されてますから実際は16本)、さらに2期分で、計28本 合計84時間!

WWDC 2010のビデオと同じくらいオススメの内容です。

iTunesのリンクが正常に動作しないようで、以下のリンクをクリックしてもiTunes Uに飛べるとは限りません。iTunesでAdvanced iPhone Developmentを検索しましょう。


■Advanced iPhone Development - Spring 2010 http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=407243032
Course Notes

■Advanced iPhone Development - Fall 2010 http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=407243028


たとえば


Fall 2010 12. Multithreading, multitasking, and GCD
35分くらいマルチタスキング、1時間5分くらいみっちりスレッド。1時間10分以上Grand Central Dispatch。スレッド部分で、performSelectorInBackgroundの説明とともに、Race Conditionなどスレッドプログラミングにおける基本をみっちりやって、NSOperationQueueの使い方。そしてGrand Central Dispatchでどれだけ楽になるか。という流れ。

Spring 2010 12. OpenGL ES, Fall 2010 13. OpenGL ES 2.0
OpenGL ES 1.1、OpenGL ES 2.0を網羅。画面を確認しながらvertex shader、fragment shaderを説明。なかなか見かけない講座です。

Sprint 2010 14 Guest Speaker, Fall 2010 14. Selling iOS applications
アプリの売り方、プロモーションについて、売上の推移、AdMob,iAd。これまたなかなか見られない内容です。WWDCではこういうのは見れない(笑)



あ、英語に抵抗ある人は『iOS 4プログラミングブック』をどうぞ! Blocks、Grand Central Dispatchを知りたいならコレ

2011-01-11

MacVim-KaoriYa 20110111

MacVim-KaoriYa 20110111版をリリースしました。

http://code.google.com/p/macvim-kaoriya/

http://macvim-kaoriya.googlecode.com/files/macvim-kaoriya-20110111.dmg

MacVim-KaoriYaのMacVimメニューの「アップデートを確認」よりアップデートをお試しくださいませ。

Vim 7.3.99、MacVim Snapshot 56、香り屋パッチ 20110109ベースです。

GUI実行時(MacVim.appを実行時)のIM制御のデフォルトを変更しました(Readme 日本語入力(IM)自動オン/オフ)。

set imdisableactivate


ESCでIM入力が自動でオフになりますが、再度入力モードに入っても自動でIMをオンにしなくなりました。

set noimdisableactivate


とすると、ESCでIM入力が自動でオフになり、再度入力モードに入ると自動でIMをオンにします。

set imdisable


で、IM自動制御自体を禁止します。