LoginSignup
15
15

More than 5 years have passed since last update.

RubyMotionでGCDを使う

Posted at

GCD

今日はRubyMotionでGCD(Grand Central Dispatch)を使う話です.

GCD とは

GCDというのは,

非常に効率的なシステム機能と使い勝手のよいプログラミングモデルを併用して,マルチプロセッサを最大限に活用するために必要なコードを徹底的に簡素化

するものらしいです
(AppleのGrand Central Dispatchの説明より)

UITableViewとかそういうのはMainThreadでちょっと重い処理をすると,すぐにパフォーマンスが悪くなってなんだこのアプリ糞だな!とか言われるので,そういう時には別Threadを立ててMainThreadの処理を邪魔しないように処理を行う必要があります.
それを楽にしてくれるのがGCD.

Objective-C

Obj-Cのコードだと,

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        // 処理
    });

こんな感じになります.

RubyMotion

RubyMotionでは,GCD関連はDispatchクラスを使います.

RubyMotion Runtime Guid にも書いてます.

上で書いたObj-CのコードをRubyMotionで書きなおすと,

    Dispatch::Queue.concurrent.async{
        # 処理
    }

こうなります.超簡単.

UIの更新に関して

さて,実際にはConcurrent Dispatch Queueで時間のかかる処理を行い,
処理を行った結果をUIに反映させることがよくあります.
その場合に直接UIへ値を代入とかすると落ちます.
UIはMainThreadから更新しなければなりません.
その場合は,

    Dispatch::Queue.concurrent.async{
        # 処理
        Dispatch::Queue.main.async{
            #UI更新
        }
    }

このようにDispatch::Queue.mainでMain Dispatch Queueに更新処理を入れることで実現できます.

実戦

実際に少し書いてみます.

$ motion create gcd
$ cd gcd

app/app_delegate.rb

app/app_delegate.rb
    class AppDelegate
      def application(application, didFinishLaunchingWithOptions:launchOptions)
        @window = UIWindow.alloc.initWithFrame UIScreen.mainScreen.bounds
        @window.rootViewController = NSBundle.mainBundle.loadNibNamed(
            'RootViewController', 
            owner: self,
            options: nil).first
        @window.rootViewController.wantsFullScreenLayout = true
        @window.makeKeyAndVisible
        true
      end
    end

InterfaceBuilder

resouces/RootViewController.xib という形でUIButton(Tag 2),UILabel(Tag 1)を追加しておいて下さい.
(参考:[RUBYMOTION] INTERFACEBUILDERと合わせて使って楽をしよう

app/root_view_controller.rb

app/root_view_controller.rb
    class RootViewController < UIViewController
        def viewDidLoad
            @label = view.viewWithTag 1
            @button = view.viewWithTag 2
            @button.addTarget(
                self,
                action: 'onClicked:',
                forControlEvents:UIControlEventTouchUpInside)
        end

        def onClicked(sender)
            p "onClicked"

            Dispatch::Queue.concurrent.async {
                NSThread.sleepForTimeInterval 5
                Dispatch::Queue.main.async {
                    @label.text = ["hoge", "fuga", "moge"].sample
                }
            }
        end
    end

実行

$ rake

シミュレータが立ち上がり,Buttonを押すとLabelの文字列がちょっと待ったあとに変わります.
連打すると次々変わると思います.
その間Buttonが押せないとかそういうことが起こらないのが分かると思います.

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15