Download - Objc lambda
Objective-Cde
lambda1
松浦 明彦 @matu_ani
13年9月4日水曜日
自己紹介•コップ本読んでる途中な程度•札幌C++勉強会メンバー(最年長w)• 「プログラミングの魔導少女」:巻末記事•監修メンバー• 「C++の設計と進化」(通称:D&E)• 「ストラウストラップのプログラミング入門」(通称:鈍器w)
•ジャズと酒が趣味、シングルパパです。2
13年9月4日水曜日
お話しすること・ねらい• Objective-Cの紹介がてら、関数型つながりでObjective-Cのラムダ式(Blocks)についてお話します。
• めざせBlocks完全制覇!!• 実装・シンタックス寄り、現場的なお話しです。
• 関数型的なお話は殆どありません m(_ _)m3
13年9月4日水曜日
もくじ
•Objective-C 文法基礎•Objective-C Blocks基礎•Objective-C Blocks応用•C++とBlocks
413年9月4日水曜日
Objective-C文法基礎
5
さらっと流します...
13年9月4日水曜日
• C言語にオブジェクト指向機能を追加:☓• Smalltalk風 Object Systemの言語環境にて、C言語も使うことが出来る:○• Cの言語仕様自体には、何も足さない何も引かない。
6
Objective-Cとは
13年9月4日水曜日
• C言語にオブジェクト指向機能を追加:☓• Smalltalk風 Object Systemの言語環境にて、C言語も使うことが出来る:○• Cの言語仕様自体には、何も足さない何も引かない。
6
スクリプト言語並の動的言語と静的型付け言語が共存するハイブリッドな環境
Objective-Cとは
13年9月4日水曜日
"initializeメッセージをaMyObjectに送信" aMyObject initialize. "引数30のsetSizeメッセージをaSquareに送信" aSquare setSize : 30.
"オブジェクト「3」にセレクタ「+」を引数「4」で送信" total := 3 + 4.
7
Smalltalk 例
13年9月4日水曜日
Objective-Cでのメッセージ送信•メソッド呼び出しは、メッセージ(セレクタ)送信の結果である。
// 単項メッセージ(引数なし) [receiver msg]; // receiver->msg();
// 引数付きメッセージ val = [receiver msg: arg1 with: arg2]; // val = receiver->msg( arg1, arg2 );
813年9月4日水曜日
Objective-Cでのメッセージ送信•メソッド呼び出しは、メッセージ(セレクタ)送信の結果である。
// 単項メッセージ(引数なし) [receiver msg]; // receiver->msg();
// 引数付きメッセージ val = [receiver msg: arg1 with: arg2]; // val = receiver->msg( arg1, arg2 );
“[]” で囲う
8
メッセージキーワード
13年9月4日水曜日
クラスの宣言・定義•クラスの宣言・定義には@コンパイラディレクティブを使う。
•通常、宣言部を.hファイル、実装部を.mファイルに記述する。(一緒でもよい)
• #importは#includeと基本同じだが、二重includeしない。
913年9月4日水曜日
#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日水曜日
#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日水曜日
制御構文
• if,while,for,とか、JavaやC++と同じ。 AlarmFake* f = [[AlarmFake alloc]init]; if( [f conformsToProtocol:@protocol(Alarm)] ) {
// ・・・ }
1113年9月4日水曜日
基礎編、もうちょい
• C/C++との共存
•メモリ管理について
1213年9月4日水曜日
C/C++との共存• 普通にC/C++が使える。• C++を使う場合、.mでなく、.mmにする。(ていうか基本.mmにすべし)
• boostも使える。• Xcode4.2のllvm-clangはC++11(一部)も!
1313年9月4日水曜日
#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日水曜日
メモリ管理
• Objective-Cのクラスは静的には生成できない。必ずallocする。
MyObject* obj = [[MyObject alloc] init]; [obj method :arg with:10];
1513年9月4日水曜日
参照カウンタ•難敵: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日水曜日
簡単にリークするw• release忘れ• retainしすぎ• autorelease忘れ• しかも、これらが絡み合うww
• ..... Appleが示した解決策は17
13年9月4日水曜日
Automatic Reference Counting (ARC)
18
• iOS5、MacOSX10.6から • Xcode4.2ではデフォルト• 参照カウンタ管理をコンパイル時に解決してくれる。ヽ(^。^)ノ
• retain/release/retainCount等は書かなくていい。• てか、書いたらコンパイルエラー orz• GCとは別(GCもオプションであり)
13年9月4日水曜日
その他の機能• ランタイムシステム• プロパティ• プロトコル• カテゴリ• クラスエクステンション• クラスクラスタ• 例外• GC• 高速列挙• ・・・などなど、あと、フレームワークには一切触れてません
1913年9月4日水曜日
Objective-CBlocks
2013年9月4日水曜日
Blocks基礎
2113年9月4日水曜日
Blocksって
•ようはラムダです。• ラムダ式のリテラル•MacOSX 10.6/iOS 4.0以降• AppleのC言語の拡張• http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1370.pdf
2213年9月4日水曜日
Declaring a Block
23
• シンタックスはCの関数ポインタと似ている。• “^” を使う。
13年9月4日水曜日
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日水曜日
パラメータにBlock
25
void blocks_caller( void (^f)(void) ){! f();}
void blocks_test(){! blocks_caller( ^(){ NSLog(@"test1");} );}
13年9月4日水曜日
Blocksどーよ•最近のCocoaAPI は積極的にBlockを使う傾向にある(iCloud APIとか)。
•なんだかんだメモリ管理を意識。Automatic Reference Counting (ARC) のもとで使うのが良さそう。
•過渡期っぽい.....が、今後は重要なプログラミングスタイルと思われ。
2613年9月4日水曜日
Blocks応用
27
といっても、キャプチャとかBlockの寿命とかそのへん
13年9月4日水曜日
変数のキャプチャ
•ローカル変数、グローバル変数をBlock内で使用可能
•ローカル変数はデフォルトで、イミュータブル、かつBlock構築時のコピー
2813年9月4日水曜日
キャプチャの例
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日水曜日
ミュータブルで共有なキャプチャ
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日水曜日
クラスで使う
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日水曜日
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日水曜日
高階関数、部分適用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日水曜日
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日水曜日
Blocks大事なこと• Blockの生存期間はそのスタックと同じ。•スタック外で使うならコピーが必要。• Block_copy / Block_release• ただ、コピーしなくてもコンパイル通る(事が多い)し、動くから恐ろしい。
• ARCのもとでは Block_copy / Block_release 不要。
• てかコンパイルエラーになる35
13年9月4日水曜日
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日水曜日
軽くまとめ• ローカル変数のキャプチャはデフォルトでイミュータブルかつBlock構築時のコピー。
• __block修飾されたローカル変数は、ミュータブルとなり、そのスタック内のblockで共有される。
• Blockの寿命はスタックと同じ。スタック外でも使いたければcopyが必要。
• ARCが吉37
13年9月4日水曜日
BlocksとC++
38
実はここを一番話したかったという噂もw...
13年9月4日水曜日
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日水曜日
簡易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日水曜日
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日水曜日
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日水曜日
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日水曜日
ご清聴ありがとうございました
4313年9月4日水曜日