Skip to content


iPhoneでラジオボタン

iPhone/iPadのネイティブアプリでフォームっぽいUIを使いたくなることが多いのですが、UIKitにはなぜかラジオボタンがなくていっつも困るので簡単なラジオボタンを実装してみました。
RadioButton

サンプルのプロジェクトをgithubにあげときました。

RadioButtonViewController.m
グループIDとグループ内での番号を指定してラジオボックスのUIを初期化します。

RadioButton *rb1 = [[RadioButton alloc] initWithGroupId:@"first group" index:0];
RadioButton *rb2 = [[RadioButton alloc] initWithGroupId:@"first group" index:1];
RadioButton *rb3 = [[RadioButton alloc] initWithGroupId:@"first group" index:2];

rb1.frame = CGRectMake(10,30,22,22);
rb2.frame = CGRectMake(10,60,22,22);
rb3.frame = CGRectMake(10,90,22,22);

[self.view addSubview:rb1];
[self.view addSubview:rb2];
[self.view addSubview:rb3];

// 選択値が変わったときに、delegateメソッドが呼ばれるようにする
[RadioButton addObserverForGroupId:@"first group" observer:self];

RadioButton.h
ラジオボタンの選択状態が変わったときに呼ばれるdelegateメソッドの宣言は下記。

@protocol RadioButtonDelegate <NSObject>
-(void)radioButtonSelectedAtIndex:(NSUInteger)index inGroup:(NSString*)groupId;
@end

RadioButtonViewController.m
実装例。単にグループIDとグループ内の何番目のラジオボタンが押されたかを表示

-(void)radioButtonSelectedAtIndex:(NSUInteger)index inGroup:(NSString *)groupId{
    NSLog(@"changed to %d in %@",index,groupId);
}

実装してみて思ったのは、今回はRadioButtonというUIViewのサブクラスに全部いれこんだんですが、ホントはラジオボタン間のやりとりを別クラス(RadioButtonGroupとか)にしといたほうがよいかもとか、ラベルとかも一緒に(textViewとかプロパティつくって)管理したほうがよいかもとか。。。まあ、Quick&Dirtyで行きましょう。

Posted in Programming. Tagged with , , , , , .

クロージャーを使ったデータのキャッシュ

「jQueryで新し要素を作って、ページに追加する。」よくあるパターンですが、そのたびにHTML文字列組み立ててたら、なんかパフォーマンスを犠牲にしているような気がしていたので、最近実装したAjaxのアプリでは下記のようにクロージャーでデータをキャッシュするようにした。

ここではhtmlTemplateに割り当てられているfunctionオブジェクトは、(function(){….}())内部でreturnされているfunction。function(){}()というのは無名functionを生成するのと同時に実行するという意味で、大外の()はシンタックス的には不要なんですが、var hoge = function(){};のように単純に変数に関数を代入するのとは「なんか違うぞ」という事を示すコンベンションなんだとか。

return される関数はfunctionの外側の変数(htmlとか)を参照でき、呼出しの度にhtml(の文字列の配列)を初期化するわけではなく、初回に実行されたhtmlを使いまわせる。

Posted in Programming. Tagged with , .

gitignore集

Android+Eclipse用のgit設定を探していたら、便利なサイトを見つけたのでメモ。

.gitignore
様々なタイプのプロジェクトに必要な.gitignoreを集めているサイト

github/gitignore – GitHub A collection of useful .gitignore templates
gitignoreを集めたリポジトリ

とりあえずこれを使うことにしました。

# built application files
*.apk
*.ap_

# files for the dex VM
*.dex

# Java class files
*.class

# generated GUI files
*R.java

Posted in Programming. Tagged with , .

TextmateでちょっとしたObjective-Cのコードを実行する

TextMateでコンパイル&実行までできることに気づいたのでメモ。

test.mというファイル名でファイルを作成した後、”Select Bundle Item”ダイアログをひらいてみる(ショートカットは^⌘T)。Cのメイン関数を挿入するスニペットがあるので、
それを使うとだいたい出来上がり。

textnte-objc-cmd

textmate-objc

⌘Rでコンパイル&実行できる。

textmate-objc-run

ちなみに、上記の手順の場合、TextMateのバンドルはCのものを使っているみたいで、コンパイルは下記のようなオプションで実行されているみたいです。

gcc test.m -Wall -include stdio.h -framework Cocoa

Posted in Programming. Tagged with , , .

Objective-CでクラスメソッドをMockする

OCMockは素晴らしいライブラリだと思いますが、クラスメソッドにMock/Stub設定できなくて(※)困る時があります。

※OCMockの使用例(http://svn.mulle-kybernetik.com/OCMock/trunk/Source/OCMockObjectTests.m)にないのでおそらくOCMockでは無理、もしくはまだ機能として組み込んでないんだろうと思います。

ただ、Objective-Cはセレクタ(メソッドの名前のようなもの)とメソッドの実装のマッピングを、ランタイムAPIを使って実行時に変更できるので、これを使えばやりたい事はだいたい実現できます。(Method Swizzlingというらしいです)

メソッド交換すると、おそらく実行されるコンテキスト(ローカル/インスタンス変数、self etc)が変わると思うので、モックが実行されたかをチェックするフラグは、テストクラスのクラスメソッドにしてます。

Posted in Programming. Tagged with , , .

MockとStubの違い

iPhone用のUnit Testライブラリを調べていて、MockとStubの違いがあやふやになってきたので、Railsに立ち返ろうと調べてみると分かりやすいエントリがあった。

RSpec の Mock と Stub が最初分からなかったけど、理解できたら すごい! という気持ちになった
http://d.hatena.ne.jp/takihiro/20081023/1224762895

自分なりのまとめ

モック

オブジェクトの呼び出し方(使用方法)を検証する。テスト対象のコードが、ある外部クラスを正しく呼び出しているかどうかかを検証するために使用する。テスト対象のコードが使用している外部クラスにexpectation(RSpecでは.should_receive)を設定する。

スタブ

テスト対象のコードの中で外部クラスを参照する場合に、外部クラスが単純なデータを返すことを設定する。

Posted in Programming. Tagged with , , , , .

RackでHTTPリクエストを確認

全然用途が違うとおもったのですが、iPhoneのUIWebViewやmobile Safariがどういうリクエストを投げているか確認するために、リクエストHeaderを表示する簡単なRackアプリを作ってみた。



PCのブラウザ(Firefox)でアクセスすると、こんな感じです。


GATEWAY_INTERFACE: CGI/1.1
HTTP_ACCEPT: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_CHARSET: Shift_JIS,utf-8;q=0.7,*;q=0.7
HTTP_ACCEPT_ENCODING: gzip,deflate
HTTP_ACCEPT_LANGUAGE: ja,en-us;q=0.7,en;q=0.3
HTTP_CONNECTION: keep-alive
HTTP_HOST: localhost:9923
HTTP_KEEP_ALIVE: 115
HTTP_USER_AGENT: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
HTTP_VERSION: HTTP/1.1
PATH_INFO: /
QUERY_STRING:
REMOTE_ADDR: ::1
REMOTE_HOST: localhost
REQUEST_METHOD: GET
REQUEST_PATH: /
REQUEST_URI: http://localhost:9923/
SCRIPT_NAME:
SERVER_NAME: localhost
SERVER_PORT: 9923
SERVER_PROTOCOL: HTTP/1.1
SERVER_SOFTWARE: WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)
rack.errors: #
rack.input: #
rack.multiprocess: false
rack.multithread: true
rack.run_once: false
rack.url_scheme: http
rack.version: 11



下記は、シュミレータで試したときのスクリーンショット


iphone_sim


GATEWAY_INTERFACE: CGI/1.1
HTTP_ACCEPT: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
HTTP_ACCEPT_ENCODING: gzip, deflate
HTTP_ACCEPT_LANGUAGE: en-us
HTTP_CACHE_CONTROL: max-age=0
HTTP_CONNECTION: keep-alive
HTTP_HOST: localhost:9923
HTTP_USER_AGENT: Mozilla/5.0 (iPhone Simulator; U; CPU iPhone OS 4_0_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A306 Safari/6531.22.7
HTTP_VERSION: HTTP/1.1
PATH_INFO: /
QUERY_STRING:
REMOTE_ADDR: ::1
REMOTE_HOST: localhost
REQUEST_METHOD: GET
REQUEST_PATH: /
REQUEST_URI: http://localhost:9923/
SCRIPT_NAME:
SERVER_NAME: localhost
SERVER_PORT: 9923
SERVER_PROTOCOL: HTTP/1.1
SERVER_SOFTWARE: WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)
rack.errors: #
rack.input: #
rack.multiprocess: false
rack.multithread: true
rack.run_once: false
rack.url_scheme: http
rack.version: 11 

Posted in Programming. Tagged with , , , .

Nginx,Thin,Rails/Sinatraの設定

RubyでRailsやEventMachineを使用したWebアプリケーションを書いていると、同じドメインでWebアプリケーションを組み合わせたいと思ってたので、メモ。

[server] apache + passengerを捨ててnginx + thinにしてみた
[server] nginxのinitスクリプト
Nginx, rails and thin
Capistrano + Nginx + Thin deployment on Linode

Posted in Uncategorized.

EventMachineを触ってみた

機会があったので、以前から少し気になっていたEventMachineを触ってみました。EventMachineがどんなものかというのは下記のスライドに簡単にまとまっています。(いつもお世話になってるWebサービスで結構使用されてます)

EventMachine: scalable non-blocking i/o in ruby

Githubにあるeventmachineのtutorialにあるリンクをテキトーに見てみました。

まずは、一番簡単な例
An EventMachine Tutorial”

require "rubygems"
require "eventmachine"

# From "An EventMachine Tutorial"
# http://20bits.com/articles/an-eventmachine-tutorial/

# ハンドラー
module EchoServer
  # connectionからデータを受け取った時に呼び出されるメソッド
  def receive_data(data)
    # receive_dataを呼び出したconnectionにデータを返す
    # receive_dataしたらsend_dataする
    send_data(data)
  end
end

# イベントループ開始
# EventMachine::stop_event_loopを呼び出すまで止まらない
EventMachine::run do
  host = '0.0.0.0'
  port = 8080

  # 3番目の引数はHandlerで、コールバック用の関数でグローバル変数を汚染しないために
  # moduleを定義することが多い。
  EventMachine::start_server host,port,EchoServer
  puts "started EchoServer on #{host}:#{port}"
end

このスクリプトを実行させておいて、”telnet 0.0.0.0 8080″で繋げれば、入力したものがそのまま返されます。

おなじく、An EventMachine Tutorial”
にあるサーバーの例

require "rubygems"
require "eventmachine"

# From "An EventMachine Tutorial"
# http://20bits.com/articles/an-eventmachine-tutorial/

class Server < EventMachine::Connection
  attr_accessor :status,:options

  def receive_data
    puts "#{@status} -- #{data}"
    send_data("hello\n")
  end
end

EventMachine::run do
  # start_serverは3番目の引数に指定されたハンドラーを引数にyeildする
  EM::start_server host,port,Server do |conn|
    conn.options = {:my => 'options'}
    conn.status = :OK
  end
end

この例では、Serverクラスをハンドラーに指定しています。EventMachine::start_serverは任意のモジュールかクラスをハンドラーに指定することができます。モジュールを指定した場合もEventMachine::Connectionクラスにそのモジュールがインクルードされた後、接続したクライアントごとにインスタンス化されます。

そこらへんはEventMachineのソースを追いつつ、絵を描いてたのですが、自分でも微妙な絵になってしまった。。。
とはいえ、一応さらしておきます。
EventMachine

今度もおなじく、An EventMachine Tutorial”ですが、httpクライアントの例

require "rubygems"
require "eventmachine"

# From "An EventMachine Tutorial"
# http://20bits.com/articles/an-eventmachine-tutorial/

module HttpHeaders
  # connectionがセットアップされた直後に呼び出される。
  # クライアントアプリならサーバーにつながった直後/サーバーアプリならクライアントが接続してきた直後
  def post_init
    send_data "GET /\r\n\r\n"
    @data = ""
  end

  def receive_data(data)
    @data << data
  end

  # クライアント/サーバー側のいずれかの接続が終了した時
  # このhttp_clientの場合は、サーバーがデータを送り終えたら呼び出される
  def unbind
    puts "server have sent data"
    if @data =~ /[\n][\r]*[\n]/m
      $`.each do |line|
        puts ">>> #{line}"
      end
    end

    # ループを終了させる
    EventMachine::stop_event_loop
  end
end

EventMachine::run do
  EventMachine::connect "google.com",80,HttpHeaders
end

ポイントとしては、

  • 接続の開始時にpost_init/終了時にunbindが実行される
  • TCPはストリームなので、receive_dataは何度も実行され、渡されるデータの単位は(改行区切りとか)意味のあるものではない
  • というところでしょうか。

    今度は、Playing with EventMachineにあるタイマーの設定例

    require "rubygems"
    require "eventmachine"
    
    # Playing with EventMachine
    # http://everburning.com/news/playing-with-eventmachine/
    
    # EventMachineとEMは同じ
    # runでイベントループが開始されるが、引数として渡されるブロックをその前に実行する
    EventMachine::run do
      # 定期的に実行されるタイマーを設定
      EM.add_periodic_timer(1) { puts "Tick ..." }
    
      # 指定した秒数が経過した後に、1回実行されるタイマーを設定
      EM.add_timer(3) do
        puts "I waited 3 seconds"
        EM.stop_event_loop
      end
    end
    
    puts "All done"
    

    一応試してみたコードはGithubにアップしてます。em_snipett
    もうちょっとわかってきたら、アップデートします。

Posted in Programming. Tagged with , .

O3DがJavascriptライブラリに

これはすごい、Webブラウザでネイティブに3Dが実現できる環境が近づいて来た。
Great win for WebGL and standards; O3D becomes JS library

Javascriptの高速化とWebGLの実装が進んできたことで、O3DもJavascriptでの実装に切り替えるとのこと。
1年ほど前にO3Dのデモを試したときは、かなりPCが熱くなっていたのでまだまだパフォーマンスの問題とか、3Dコンテンツ制作ツール(と3Dモデルの保存形式とか)の問題はありそうですが、大きな全身ですね。

Posted in Technology. Tagged with , .