objc lambda

47
Objective-C de lambda 1 松浦 明彦 @matu_ani 1394日水曜日

Upload: akihiko-matuura

Post on 24-Dec-2014

451 views

Category:

Documents


7 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Objc lambda

Objective-Cde

lambda1

松浦 明彦 @matu_ani

13年9月4日水曜日

Page 2: Objc lambda

自己紹介•コップ本読んでる途中な程度•札幌C++勉強会メンバー(最年長w)• 「プログラミングの魔導少女」:巻末記事•監修メンバー• 「C++の設計と進化」(通称:D&E)• 「ストラウストラップのプログラミング入門」(通称:鈍器w)

•ジャズと酒が趣味、シングルパパです。2

13年9月4日水曜日

Page 3: Objc lambda

お話しすること・ねらい• Objective-Cの紹介がてら、関数型つながりでObjective-Cのラムダ式(Blocks)についてお話します。

• めざせBlocks完全制覇!!• 実装・シンタックス寄り、現場的なお話しです。

• 関数型的なお話は殆どありません m(_ _)m3

13年9月4日水曜日

Page 4: Objc lambda

もくじ

•Objective-C 文法基礎•Objective-C Blocks基礎•Objective-C Blocks応用•C++とBlocks

413年9月4日水曜日

Page 5: Objc lambda

Objective-C文法基礎

5

さらっと流します...

13年9月4日水曜日

Page 6: Objc lambda

• C言語にオブジェクト指向機能を追加:☓• Smalltalk風 Object Systemの言語環境にて、C言語も使うことが出来る:○• Cの言語仕様自体には、何も足さない何も引かない。

6

Objective-Cとは

13年9月4日水曜日

Page 7: Objc lambda

• C言語にオブジェクト指向機能を追加:☓• Smalltalk風 Object Systemの言語環境にて、C言語も使うことが出来る:○• Cの言語仕様自体には、何も足さない何も引かない。

6

スクリプト言語並の動的言語と静的型付け言語が共存するハイブリッドな環境

Objective-Cとは

13年9月4日水曜日

Page 8: Objc lambda

"initializeメッセージをaMyObjectに送信" aMyObject initialize. "引数30のsetSizeメッセージをaSquareに送信" aSquare setSize : 30.

"オブジェクト「3」にセレクタ「+」を引数「4」で送信" total := 3 + 4.

7

Smalltalk 例

13年9月4日水曜日

Page 9: Objc lambda

Objective-Cでのメッセージ送信•メソッド呼び出しは、メッセージ(セレクタ)送信の結果である。

// 単項メッセージ(引数なし) [receiver msg]; // receiver->msg();

// 引数付きメッセージ val = [receiver msg: arg1 with: arg2]; // val = receiver->msg( arg1, arg2 );

813年9月4日水曜日

Page 10: Objc lambda

Objective-Cでのメッセージ送信•メソッド呼び出しは、メッセージ(セレクタ)送信の結果である。

// 単項メッセージ(引数なし) [receiver msg]; // receiver->msg();

// 引数付きメッセージ val = [receiver msg: arg1 with: arg2]; // val = receiver->msg( arg1, arg2 );

“[]” で囲う

8

メッセージキーワード

13年9月4日水曜日

Page 11: Objc lambda

クラスの宣言・定義•クラスの宣言・定義には@コンパイラディレクティブを使う。

•通常、宣言部を.hファイル、実装部を.mファイルに記述する。(一緒でもよい)

• #importは#includeと基本同じだが、二重includeしない。

913年9月4日水曜日

Page 12: Objc lambda

#import <Foundation/Foundation.h>

// クラスの宣言@interface MyClass : NSObject { int val;}- (id)init;+ (void)classMethod:(id)arg; // クラスメソッド- (id)method:(NSObject*)arg1 with:(int)arg2;@end

// 実装@implementation MyClass+ (void)classMethod:(id)arg { // some operation}- (id)method:(NSObject*)arg1 with:(int)args2 { return obj;}@end

1013年9月4日水曜日

Page 13: Objc lambda

#import <Foundation/Foundation.h>

// クラスの宣言@interface MyClass : NSObject { int val;}- (id)init;+ (void)classMethod:(id)arg; // クラスメソッド- (id)method:(NSObject*)arg1 with:(int)arg2;@end

// 実装@implementation MyClass+ (void)classMethod:(id)arg { // some operation}- (id)method:(NSObject*)arg1 with:(int)args2 { return obj;}@end

1013年9月4日水曜日

Page 14: Objc lambda

制御構文

• if,while,for,とか、JavaやC++と同じ。 AlarmFake* f = [[AlarmFake alloc]init]; if( [f conformsToProtocol:@protocol(Alarm)] ) {

// ・・・ }

1113年9月4日水曜日

Page 15: Objc lambda

基礎編、もうちょい

• C/C++との共存

•メモリ管理について

1213年9月4日水曜日

Page 16: Objc lambda

C/C++との共存• 普通にC/C++が使える。• C++を使う場合、.mでなく、.mmにする。(ていうか基本.mmにすべし)

• boostも使える。• Xcode4.2のllvm-clangはC++11(一部)も!

1313年9月4日水曜日

Page 17: Objc lambda

#import <Foundation/Foundation.h>#include <iostream>#include <boost/shared_ptr.hpp>

class CppClass{public:! CppClass(){}! void print() const { ! ! std::cout << "CppClass::print" << std::endl; ! }};

@interface ObjcClass : NSObject- (void)print;@end@implementation ObjcClass- (void)print {! NSLog(@"ObjcClass print");}@end

void boost_test(){! boost::shared_ptr<CppClass> p(new CppClass);!! ObjcClass* oc = [[ObjcClass alloc]init];!! [oc print]; // ObjcClass print! p->print(); // CppClass::print}

14

C++のクラス

Objective-Cのクラス

13年9月4日水曜日

Page 18: Objc lambda

メモリ管理

• Objective-Cのクラスは静的には生成できない。必ずallocする。

MyObject* obj = [[MyObject alloc] init]; [obj method :arg with:10];

1513年9月4日水曜日

Page 19: Objc lambda

参照カウンタ•難敵:retain,release,autorelease

MyObject* obj = [[MyObject alloc] init]; // 参照カウント1 [obj retain]; // 参照カウント2 NSLog(@"count=%d", [obj retainCount] ); // count=2 [obj release] ; // 参照カウント1 [obj release] ; // 参照カウント0,開放される・・・ // メモリプールが有効なあいだ生きてる MyObject* obj = [[[MyObject alloc] init] autorelease]; [obj retain]; // 参照カウント2、メモリプールの生き死に関わらず保持したい!

1613年9月4日水曜日

Page 20: Objc lambda

簡単にリークするw• release忘れ• retainしすぎ• autorelease忘れ• しかも、これらが絡み合うww

• ..... Appleが示した解決策は17

13年9月4日水曜日

Page 21: Objc lambda

Automatic Reference Counting (ARC)

18

• iOS5、MacOSX10.6から • Xcode4.2ではデフォルト• 参照カウンタ管理をコンパイル時に解決してくれる。ヽ(^。^)ノ

• retain/release/retainCount等は書かなくていい。• てか、書いたらコンパイルエラー orz• GCとは別(GCもオプションであり)

13年9月4日水曜日

Page 22: Objc lambda

その他の機能• ランタイムシステム• プロパティ• プロトコル• カテゴリ• クラスエクステンション• クラスクラスタ• 例外• GC• 高速列挙• ・・・などなど、あと、フレームワークには一切触れてません

1913年9月4日水曜日

Page 23: Objc lambda

Objective-CBlocks

2013年9月4日水曜日

Page 24: Objc lambda

Blocks基礎

2113年9月4日水曜日

Page 25: Objc lambda

Blocksって

•ようはラムダです。• ラムダ式のリテラル•MacOSX 10.6/iOS 4.0以降• AppleのC言語の拡張• http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1370.pdf

2213年9月4日水曜日

Page 26: Objc lambda

Declaring a Block

23

• シンタックスはCの関数ポインタと似ている。• “^” を使う。

13年9月4日水曜日

Page 27: Objc lambda

Using a Block

24

void (^b1)(int) = ^(int x){NSLog(@"Hello Blocks %d",x);};b1(100); // Hello Blocks 100

// パラメータ無しなら定義側は()を省略してもOKvoid (^b2)() = ^{NSLog(@"Hello Blocks 2");};b2(); // Hello Blocks 2

13年9月4日水曜日

Page 28: Objc lambda

パラメータにBlock

25

void blocks_caller( void (^f)(void) ){! f();}

void blocks_test(){! blocks_caller( ^(){ NSLog(@"test1");} );}

13年9月4日水曜日

Page 29: Objc lambda

Blocksどーよ•最近のCocoaAPI は積極的にBlockを使う傾向にある(iCloud APIとか)。

•なんだかんだメモリ管理を意識。Automatic Reference Counting (ARC) のもとで使うのが良さそう。

•過渡期っぽい.....が、今後は重要なプログラミングスタイルと思われ。

2613年9月4日水曜日

Page 30: Objc lambda

Blocks応用

27

といっても、キャプチャとかBlockの寿命とかそのへん

13年9月4日水曜日

Page 31: Objc lambda

変数のキャプチャ

•ローカル変数、グローバル変数をBlock内で使用可能

•ローカル変数はデフォルトで、イミュータブル、かつBlock構築時のコピー

2813年9月4日水曜日

Page 32: Objc lambda

キャプチャの例

29

int g=999; // グローバル変数・・・ int x = 100; void (^b)() = ^(){NSLog(@"x=%d g=%d",x,g);}; b(); // x=100 g=999

x=200; b(); // x=100(変わらず) g=888; b(); // x=100 g=888

13年9月4日水曜日

Page 33: Objc lambda

ミュータブルで共有なキャプチャ

30

__block int x=100; void (^b)() = ^(){NSLog(@"x=%d g=%d", x++, g);}; b(); // x=100 g=999 b(); // x=101 g=999 x=200; b(); // x=200 g=999

13年9月4日水曜日

Page 34: Objc lambda

クラスで使う

31

@interface testClass : NSObject{ int x_;}-(void) myprint;-(void) print:(void(^)(int x))printer;@end

@implementation testClass-(void)print:(void (^)(int x))printer { printer(x_); }

testClass* t = [[testClass alloc]init]; [t print:^(int x){ NSLog(@"my printer x=%d", x);}];

13年9月4日水曜日

Page 35: Objc lambda

selfのキャプチャ

32

-(void)myprint { // testClassのメソッド x_ = 100; void(^b)()=^{ NSLog(@"x_=%d", x_);}; b(); // x_ = 100

x_ = 200; b(); // x_ = 200 !!(コピーと違うの??)

// こう書いているのと同じ void(^b2)()=^{ NSLog(@"testClass x_=%d", self->x_);};}

• メンバー変数がキャプチャされているのではない• selfがキャプチャされている!

13年9月4日水曜日

Page 36: Objc lambda

高階関数、部分適用Func<int, Func<int, int>> f = x => y => x + y;Func<int, int> fc = f(1);int x = fc(3); // 4 (1 + 3)

C#

auto f = [](int x){ return [x](int y){return x+y;}; };auto fc = f(1);int x = fc(3); // 4 (1 + 3)

C++11

3313年9月4日水曜日

Page 37: Objc lambda

Blockだと。。void blocks_test(){! typedef int (^add_function)(int);! add_function (^f)(int) = ! ! ! ! ! ^(int x){ ! ! ! ! ! ! return Block_copy(^(int y){ return x+y;}); ! ! ! ! ! };

! add_function fc = f(1);! NSLog(@"blocks_test() fc=%d", fc(3)); // 4 (1 + 3)! Block_release(fc);}

3413年9月4日水曜日

Page 38: Objc lambda

Blocks大事なこと• Blockの生存期間はそのスタックと同じ。•スタック外で使うならコピーが必要。• Block_copy / Block_release• ただ、コピーしなくてもコンパイル通る(事が多い)し、動くから恐ろしい。

• ARCのもとでは Block_copy / Block_release 不要。

• てかコンパイルエラーになる35

13年9月4日水曜日

Page 39: Objc lambda

ARCありなら...void blocks_test(){! typedef int (^add_function)(int);! add_function (^f)(int) = ^(int x){return ^(int y){return x+y;};};! add_function fc = f(1);! NSLog(@"blocks_test() fc=%d", fc(3)); // 4 (1 + 3)}

36

すっきり(^^)

13年9月4日水曜日

Page 40: Objc lambda

軽くまとめ• ローカル変数のキャプチャはデフォルトでイミュータブルかつBlock構築時のコピー。

• __block修飾されたローカル変数は、ミュータブルとなり、そのスタック内のblockで共有される。

• Blockの寿命はスタックと同じ。スタック外でも使いたければcopyが必要。

• ARCが吉37

13年9月4日水曜日

Page 41: Objc lambda

BlocksとC++

38

実はここを一番話したかったという噂もw...

13年9月4日水曜日

Page 42: Objc lambda

C++11のfunction<T>にBlockを

39

std::function<void(int)> f = ^(int x){NSLog(@"Hello function!! x=%d",x);};

f(1); // Hello function!! x=1 f(2); // Hello function!! x=2

std::function<T>は、Blocks対応に書き換えてあるのかな??

13年9月4日水曜日

Page 43: Objc lambda

簡易function作った

40

template<typename R, typename ...V>struct my_function { struct HolderBase{ virtual R run(V... arg)=0; }; template<typename F> struct Holder : HolderBase { F f_; Holder(F f):f_(f){} virtual R run(V... arg) { return f_(arg...); } }; boost::scoped_ptr<HolderBase> holder_; template<typename F> my_function(F f) : holder_(new Holder<F>(f) ){} R operator()(V... arg) { holder_->run(arg...); }};

13年9月4日水曜日

Page 44: Objc lambda

my_functionにも

41

my_function<void,int> mf(^(int x){NSLog(@"my_function!! x=%d",x);});

mf(100); // my_function!! x=100

• my_functionにBlocks固有のコードは無い。• BlocksはObjC固有の型だが、C++のジェネリック型システムはそれを吸収した(とも言えるかと)。

• 無論、std::functionは変更不要(のはず)。

13年9月4日水曜日

Page 45: Objc lambda

C++11 autoで型推論

42

// blockをautoで型推論auto af = ^(int x){NSLog(@"Hello C++11 auto!! x=%d",x);};af(5); // Hello C++11 auto!! x=5

// 高階関数も楽チンauto f = ^(int x){ return ^(int y){ return x+y;};};auto fc = f(1);NSLog(@"Hello C++11 auto!! fc=%d",fc(3)); // fc=4

13年9月4日水曜日

Page 46: Objc lambda

C++11 autoで型推論

42

やっぱC++かわいいw

// blockをautoで型推論auto af = ^(int x){NSLog(@"Hello C++11 auto!! x=%d",x);};af(5); // Hello C++11 auto!! x=5

// 高階関数も楽チンauto f = ^(int x){ return ^(int y){ return x+y;};};auto fc = f(1);NSLog(@"Hello C++11 auto!! fc=%d",fc(3)); // fc=4

13年9月4日水曜日

Page 47: Objc lambda

ご清聴ありがとうございました

4313年9月4日水曜日