今更の感が強いですが、Nexus 7を買いました。
いろいろな方が言及されているように、電源ボタンが使いにくいです。
手探りで音量ボタンと区別が付くようにするために、ちょこっと手を加えて見ました。
写真だと見にくいですが、ブリスターパックのプラスチックを切って両面テープで貼りつけただけ。
端がチクチクするので黒のビニールテープを貼ったのが以下。
電源ボタンを考慮したカバーなどもあるんだろうけど、しばらくこれで。
明るい所で見ると裏側は焦げ茶というかえび色というか、そういう色なんですね。
About this Blog
This Blog has English posts and Japanese posts. About Mac, iOS, Objective-C, and so on.
2013年3月28日木曜日
2013年3月24日日曜日
mruby on Objective-C -スクリプトの実行を中断-
正しい使い方かどうかは分かりませんが、一応公開します。
mruby VMがメインスレッド以外で実行されていること。
その関数の中でエラーをraiseしてスクリプトの実行を中断。
viewController.h
viewController.m
必要なコードのみ書いてあります。
前提
mruby-master/include/mrbconf.hでdefine ENABLE_DEBUG.mruby VMがメインスレッド以外で実行されていること。
方針
ユーザーのアクションで、実行中のmruby VMのcode_fetch_hookに関数を登録。その関数の中でエラーをraiseしてスクリプトの実行を中断。
viewController.h
#import <Foundation/Foundation.h> #include "mruby.h" #include "mruby/string.h" #include "mruby/compile.h" #include "mruby/class.h" #include "mruby/value.h" #include "mruby/proc.h" #include "mruby/variable.h" #include "mruby/array.h" mrb_value mrb_printstr(mrb_state*, mrb_value);//別エントリで解説しています。 void mrb_interrupt(mrb_state*, mrb_irep*, mrb_code*, mrb_value*); @interface viewController : UIViewController{ NSOperationQueue *_queue; NSBlockOperation *_operation; struct mrb_state *_mrb; } -(void)mrbInitPrint;//別エントリで解説しています。 -(void)mrbRun:(NSString *)code;//別エントリで解説しています。 -(IBAction)mrbQuit; @end
viewController.m
必要なコードのみ書いてあります。
void mrb_interrupt(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs){ //code_fetch_hookにすぐにNULLを代入するので、この関数は1回だけ呼ばれます。 //エラーをraiseするとスクリプトが中断するので意味はないですが、 //他の処理を割りこませることもできます。 mrb->code_fetch_hook = NULL; mrb_raise(mrb, E_RUNTIME_ERROR, "interrupted"); } @implementation viewController -(IBAction)mrbQuit{ if(_mrb){ _mrb->code_fetch_hook = mrb_interrupt; } } @endUIButtonのtouch up insideなどにOutletしてください。
mruby on Objective-C - puts,pをUITextViewに出力-
方針
__printstr__を(Objective-)Cで実装し、それを使ってRubyでp,puts,print,printfを定義する。mrubyのメソッドとして使うCの関数から、AppDelegate経由でUITextViewにアクセス。
参考
- 手探りでおぼえるmruby その1:クラスを定義する、メソッドを定義する
- mruby-master/mrblib/print.rb
- mruby-master/src/print.c
Rubyのスクリプトをプロジェクトに追加しておきます。
print.rb
module Kernel # needs __printstr__ def print(*args) i = 0 len = args.size while i < len __printstr__ args[i].to_s i += 1 end end def puts(*args) i = 0 len = args.size while i < len s = args[i].to_s __printstr__ s __printstr__ "\n" if (s[-1] != "\n") i += 1 end __printstr__ "\n" if len == 0 nil end def p(*args) i = 0 len = args.size while i < len __printstr__ args[i].inspect __printstr__ "\n" i += 1 end args[0] end def printf(*args) __printstr__(sprintf(*args)) nil end end
あとは、Objective-Cを編集します。
DelegateへのUITextViewの登録、実行するRubyスクリプトの取得などは省略してあります。
また、puts,p,print,printfの度にUITextViewにsetText:するので、最後の出力しか残りません。
クラスを拡張してaddText:のようなメソッドを定義したほうが便利なはずです。
viewController.h
#import <Foundation/Foundation.h> #include "mruby.h" #include "mruby/string.h" #include "mruby/compile.h" #include "mruby/class.h" #include "mruby/value.h" #include "mruby/proc.h" #include "mruby/variable.h" #include "mruby/array.h" mrb_value mrb_printstr(mrb_state*, mrb_value); void mrb_interrupt(mrb_state*, mrb_irep*, mrb_code*, mrb_value*);//別エントリで解説します。 @interface viewController : UIViewController{ NSOperationQueue *_queue; NSBlockOperation *_operation; struct mrb_state *_mrb; } -(void)mrbInitPrint; -(void)mrbRun:(NSString *)code; -(IBAction)mrbQuit;//別エントリで解説します。 @end
viewController.m
//mruby-master/src/print.cからコピペしました。 mrb_value mrb_printstr(mrb_state *mrb, mrb_value self_){ mrb_value argv; mrb_get_args(mrb, "o", &argv); struct RString *str; char *s; int len; if(mrb_string_p(argv)){ str = mrb_str_ptr(argv); s = str->ptr; len = str->len; //以下3行を環境に応じて書き換えてください。 AppDelegate *appDel = [[UIApplication sharedApplication] delegate]; UITextView *targetView = appDel.targetTextView; [targetView performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%s",s] waitUntilDone:YES]; } return argv; } @implementation viewController -(void)mrbInitPrint{ //Kernelにp,puts,print,printfの定義に使う__printstr__を登録します。 struct RClass *krn; krn = _mrb->kernel_module; mrb_define_method(_mrb, krn, "__printstr__", mrb_printstr, ARGS_REQ(1)); //プロジェクトにバンドルしたprint.rbを読み込み、mrubyにロードします。 NSError *error = nil; NSString *script_str; NSString *path = [[NSBundle mainBundle] pathForResource:[scripts objectAtIndex:i] ofType:@"rb"]; NSString *print_rb_str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; if(!error){ mrb_load_string(_mrb, [print_rb_str cStringUsingEncoding:NSUTF8StringEncoding]); } } -(void)mrbRun:(NSString *)c{ //mruby VMの実行を別スレッドにしている以外は、参考URLの通りです。 if([_operation isExecuting]){ return; } __block NSString *code = [c copy]; if(!_queue){ _queue = [[NSOperationQueue alloc] init]; } _operation = [[NSBlockOperation alloc] init]; [_operation addExecutionBlock:^{ const char *codeStr = [code cStringUsingEncoding:NSUTF8StringEncoding]; mrbc_context *ctx; _mrb = mrb_open(); [self mrbInitPrint]; ctx = mrbc_context_new(_mrb); struct mrb_parser_state *st = mrb_parse_string(_mrb, codeStr, ctx); int gen_code_num = mrb_generate_code(_mrb, st); mrb_pool_close(st->pool); mrb_value result = mrb_run(_mrb, mrb_proc_new(_mrb,_mrb->irep[gen_code_num]), mrb_nil_value()); if(_mrb->exc){//catch exception mrb_value r = mrb_funcall(_mrb, result, "inspect", 0); if(mrb_string_p(r)){ struct RString *str = mrb_str_ptr(r); NSLog(@"%s",str->ptr); } } mrb_close(_mrb); mrbc_context_free(_mrb, ctx); _mrb = NULL; [_operation release]; _operation = nil; [code release]; }]; [_queue addOperation:_operation]; }
mruby on Objective-C -アプリに組み込む-
mrubyを使ったアプリをsubmitしたので、メモをちまちまと放出。
実機でしか動きませんのであしからず。ツッコミ大歓迎。
有効のままでも動きましたが、putsを使ったら落ちました。
DEBUGを有効にします。
これは、スクリプトの実行を中断するのに使っています。
途中でRakeが落ちますが、
mruby-master/build/32bit/lib/libmruby.a
が生成されているのでOKとします。(そのうちrake勉強せな)
mruby-master/include/をフォルダごとコピーして、そこにlibmruby.aを追加する感じです。
includeのままだと分かりにくいので、mrubyにリネームしました。
Recursiveはなしで。
以上で、iOSアプリでmrubyを使う準備は完了です。
実機でしか動きませんのであしからず。ツッコミ大歓迎。
環境
- Mac OS X 10.6.8 Snow Leopard
- Xcode4.2
- ARC不使用
- iPad2
- iOS6.1
- mruby (2013/02/17にソース取得)
方針
armv7向けにコンパイルしたmrubyの静的ライブラリを作り、それを直接Xcodeプロジェクトにコピーして使う。build_config.rbを編集
mruby-master/build_config.rbのクロスコンパイル部分を以下のように編集します。# Define cross build settings MRuby::CrossBuild.new('32bit') do |conf| isysroot = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/include" conf.cc.command = "clang" conf.cc.flags << "-arch armv7" conf.cc.include_paths << isysroot conf.cc.include_paths << "#{root}/include" end
mrbconf.hを編集
mruby-master/include/mrbconf.hを編集します。#define DISABLE_STDIO /* use of stdio */ #define ENABLE_DEBUG /* hooks for debugger */STDIOを無効にします。
有効のままでも動きましたが、putsを使ったら落ちました。
DEBUGを有効にします。
これは、スクリプトの実行を中断するのに使っています。
make
コマンドライン上でmruby-masterに移動し、makeします。途中でRakeが落ちますが、
mruby-master/build/32bit/lib/libmruby.a
が生成されているのでOKとします。(そのうちrake勉強せな)
プロジェクトを新規作成、必要ファイルをコピー
Xcodeで新しいプロジェクト(project_name)を作成し、mrubyのファイルをFinder上でコピーします。mruby-master/include/をフォルダごとコピーして、そこにlibmruby.aを追加する感じです。
includeのままだと分かりにくいので、mrubyにリネームしました。
project_name/ |--project_name.xcodeproj |--project_name/ |--mruby/ | |--mrbconf.h | |--mruby.h | |--libmruby.a | |--mruby/ | |--array.h | |--class.h | . | . | |--value.h | |--variable.h |--viewController.h |--viewController.m | . | .Finder上でコピーしたあと、Xcode上の左ペインにドラッグ・アンド・ドロップして、プロジェクトに追加します。
パスの設定
Build SettingsのHeader Search PathとLibrary Search Pathに"$(SRCROOT)/project_name/mruby"を追加します。
Recursiveはなしで。
以上で、iOSアプリでmrubyを使う準備は完了です。
登録:
投稿 (Atom)