2013年05月13日

よびだせ!Objectve-C!!

こんにちは。
ゴールデンウィークは遠出しなかったマイキーです猫

普段遠方へ行っている地元の友人がこちらに戻ってくるので……という寸法です。
こんなゴールデンウィークも有りかなぁと、のほほんいい気分(温泉)と過ごしておりましたが、どこかへ出掛けても良かったかなぁという気持ちも少々。
夏はどこかにでかけるぞぉー晴れという野望を密かに抱いておりますが、果たして夏まで持続するのかexclamation&question
ご期待下さいぴかぴか(新しい)
***

最近ふとしたきっかけでObjective-Cに触れる機会があり、ちょこちょこ勉強をするようになりました。
最初は独特な文法で面食らいましたが、習うより慣れろ精神でゴリゴリサンプルを作ったりして遊んでいます。
個人的に、メソッド呼び出し時に引数にキーワードを記述可能な所に好感が持てますグッド(上向き矢印)おそらく、引数の用途・意図を呼び出す側からも明確にする為の措置でしょうか。
キーワードを記述するとメソッド実行部分のコードが少々読みづらくなる(のは私だけ?)側面もありますが、書き方次第で可読性はいかようにでもなるので、今の所好感触です。
今後とも上手く付き合っていきたい言語ですひらめき

さて、まずはその構文の特異さに面食らったObjective-Cですが、中身も結構C/C++と違っているようです。
一つ例を挙げると、メソッド呼び出し時のジャンプ先アドレスの解決がコンパイル時ではなく、実行時に動的に行われているのだとか目
「あれ、それって遅くない?」と思われた方は正にその通りで、以下のメンバ変数を加算するメソッド「addValue」をそれぞれiPhone4Sで100万回ずつ実行した所

* C++

class Adder_cplusplus
{
public:
Adder_cplusplus(void):_value(0){}

void addValue(void){ _value += 1; }

private:
int _value;
};

void doProc(void)
{
Adder_cplusplus* pAdder = new Adder_cplusplus();
for( int i(0); i < 1000000; ++i ){
pAdder->addValue();
}
delete pAdder;
}


* Objective-C

@interface Adder_objectivec : NSObject
{
@private
int _value;
}

- (void)addValue;

@end

@implementation Adder_objectivec

- (void)addValue
{
_value += 1;
}

@end

void doProc(void)
{
Adder_objectivec* adder = [[Adder_objectivec alloc] init];
for( int i(0); i < 1000000; ++i ){
[adder addValue];
}
[adder release];
}


C++側は平均25ms、Objective-C側は平均84msと、およそ3倍強近い差がありました。
一度の呼出しでは大した差になりませんが、膨大な回数のループの中で何度も呼出される場合を考慮すると少しでもオーバーヘッドをそぎ落としたい所ですたらーっ(汗)
調べてみると、methodForSelectorやinstanceMethodForSelectorというメソッドで関数ポインタを取得出来、そこからメソッドを呼び出すとオーバーヘッドを削る事が出来るとのこと。
よし、じゃあそれやってみようexclamation×2という事で修正したObjective-Cのコードがこちら左斜め下


@interface Adder_objectivec : NSObject
{
@private
int _value;
}

- (void)addValue;

@end

@implementation Adder_objectivec

- (void)addValue
{
_value += 1;
}

@end

void doProc(void)
{
Adder_objectivec* adder = [[Adder_objectivec alloc] init];

SEL selector = @selector(addValue);
// instanceMethodForSelectorの返り値はIMP【id(*)(id, SEL, ...))】型なのでキャストする
void(*func)(id, SEL, ...) = (void(*)(id, SEL, ...))[Adder_objectivec instanceMethodForSelector:selector];

for( int i(0); i < 1000000; ++i ) {
func(adder, selector);
}
[adder release];
}


平均実行速度は平均64msに。25%程、ほんのり高速化する事が出来ました揺れるハート
ループ内で都度つど行われていたジャンプ先の検索を、事前に行うようにする事で処理速度が上昇した、という訳ですね。
メソッド呼び出し時のオーバーヘッドが実行時のボトルネックとなる事は多くありませんが、ほんんんの少しでも良いから速度を上げたい!!という時は使ってみて良いかもしれません。
高速化は細かな改善の積み重ねですので、この高速化が役に立つ日がいつか来るかも?

それではまた手(パー)

posted by 管理人 at 21:26 | プログラミング