LoginSignup
7
7

More than 5 years have passed since last update.

RubyMotion + ProMotion gemでのModal Viewの"正しい"使い方

Last updated at Posted at 2013-06-27

この手法は RubyMotion version 2.4 では解決されています!

  • Fixed a long-standing set of memory-related bugs related to lambdas. Dynamic variables (shared by lambdas and calling scope) are now allocated as heap memory inside the Proc data structure. Local variables are properly synchronized. Proc objects are properly reclaimed by the system once they are no longer used. Changes have been added to both the compiler and the runtime.

この対応によって、lambda などの中でローカル変数が参照されている場合、そのlambdaの外側のローカル変数は自動的に retain されるようになったそうです。

この対応によって なにがうれしいか? と言うと、インスタンス変数を使ってしまうと、そのインスタンスが消滅するまでメモリが消費されてしまうことや、任意のタイミングで値をセット/リセットしなければいけなくなりますが、ローカル変数だとRubyMotionのGCが適度なタイミングで解放してくれるようになります。
そのことから、長期的に見るとメモリの消費量などリソースと開発者にやさしくなるとのことです。(watson1978談)


ProMotion のドキュメントにも記述されていない上に、 ProMotion での記述方法では気付きにくいと思ったので、まとめてみました。
(すでに Objective-C などでの iOS の開発になれてる人なら、落ちる原因について想像が付くと思います)

ModalView を呼び出す側が HomeScreen 、呼び出される ModalView が ModalScreen クラスとして話を進めます。

最初にgithub上のProMotionのドキュメントにも書かれていますが、この方法だと(ModalViewを何度か開いたり閉じたりしてると)アプリが落ちたりします。

home_screen.rb
class HomeScreen < ProMotion::Screen

  def open_modal
    open ModalScreen.new, modal: true
  end

end
modal_screen.rb
class ModalScreen < ProMotion::Screen

  # close_modal はUIButtonなどのactionで呼ぶ
  def close_modal
    close 
  end

end

正しくは ↓

home_screen.rb
class HomeScreen < ProMotion::Screen

  def  open_modal
    # 一度インスタンス変数に ModalScreen を入れる
    @modal_screen = ModalScreen.new
    open @modal_screen, modal: true
  end

  # ModalScreen から dismissViewControllerAnimated:completion 経由で値を受け取れる
  def on_return args
    puts args[:value] # => :ok
  end

end
modal_screen.rb
class ModalScreen < ProMotion::Screen

  # parent_screen を用意しておくことで自動的に呼び出し元の screen をセットしてくれる
  attr_accessor :parent_screen

  def close_modal
    # parent_screen がセットされていると
    # close メソッド内で正しく dismissViewControllerAnimated:completion が呼ばれる
    close value: :ok
  end

end

一度、インスタンス変数に格納してやることで Objective-C の strong な property になります。
modal_screen = ModalScreen.new のようにローカル変数ではダメでした。
この方法で意図しないタイミングで ModalScreen のインスタンスのメモリが解放されて落ちることがなくなります。

以下、余談
下記のように書けてもいいと思うのだけれど、現状は UIWindow が返ってくるようです この PR がmergeされたので(他の機能とconflictなどすることがなければ) version 1.0 から使えそうです

home_screen.rb
class HomeScreen < ProMotion::Screen

  def open_modal
    @modal_screen = open ModalScreen.new, modal: true # => UIWindow
  end

end
7
7
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
7
7