multithreading - What is the iOS (or RubyMotion) idiom for waiting on a block that executes asynchronously? -


i have been pulling hair out weeks on niggling problem, , can't find info or tips on how or do, i'm hoping here on rubymotion forums can me out.

apologies in advance if little long, requires setup explain issues. background, i've got app uses json/rest back-end implemented ina rails app. pretty straightforward stuff. back-end working fine, , point, front end. can make calls populate model objects in rubymotion client , great.

the 1 issue of http/json libs use async calls when processing requests. fine, , understand why doing it, there couple of situations need able wait on call because need returned results before proceeding next step.

consider example user wants make payment, , have saved payment information. prior presenting user list of payment options, want make sure have latest list @ client. need make request method on user object grab current list (or timeout). don't want continue until sure list either current, or call back-end has failed. basically, want call block (without blocking ui) until results returned.

alternatives such polling changes or pushing changes back-end front not appropriate scenario. considered pulling data destination form (rather pushing form) doesn't work in particular scenario because want different things depending on whether user has zero, 1 or multiple payment options saved. need know in advance of pushing next controller, , know in advance, need make synchronous call.

my first attack create shared instance (let's call synchelper) can use store returned result of request, along "finish" state. can provide wait method spins using cfrunloopruninmode either until request finished, or until request times out.

synchelper looks bit (i've edited take irrelevant stuff out):

class synchelper   attr_accessor :finished, :result, :error   def initialize()     reset   end   def reset     @finished = false     @result   = nil     @error    = nil   end   def finished?     @finished   end   def finish     @finished = true   end   def finish_with_result(r)     @result   = r     @finished = true   end   def error?     !@error.nil?   end   def wait     timeout = 0.0     while !self.finished? && timeout < api_timeout       cfrunloopruninmode(kcfrunloopdefaultmode, api_timeout_tick, false)       timeout = timeout + api_timeout_tick     end     if timeout >= api_timeout && !self.finished?       @error = "error: timed out waiting api: #{@error}" if !error?     end   end end 

then have helper method this, allow me make call synchronous via provision of syncr instance invoked method.

def apihelper.make_sync(&block)   syncr = apihelper::synchelper.new   bubblewrap::reactor.schedule     block.call syncr   end   syncr.wait   syncr.result end 

what had hoped use async versions everywhere, in small number of cases needed synchronously, wrap call around make_sync block this:

# happens async , don't care user.async_call(...) result = apihelper.make_sync |syncr|   # 1 async default, need wait completion   user.other_async_call(...) |result|     syncr.finish_with_result(result)   end end # result (after checking errors, etc) result.do_something(...) 

importantly, want able return value 'synchronised' call invoking context, hence 'result =...' bit. if can't that, whole thing isn't use me anyway. passing in syncr, can make a call finish_with_result tell listening async task has completed, , store result there consumption invoker.

the problem make_sync , synchelper implementations stand (apart obvious fact i'm doing profoundly stupid) code inside bubblewrap::reactor.schedule ... end block doesn't called until after call syncr.wait has timed out (note: not finished, because block never gets chance run, , hence can't store result in it). starving other processes access cpu, tho call cfrunloopruninmode happening inside wait. under impression cfrunloopruninmode in config spin wait, allow other queued blocks run, appears i've got wrong.

this strikes me people need time-to-time, can't person having trouble kind of problem.

have had many crazy pills? there standard ios idiom doing i'm not understanding? there better way solve kind of problem?

any appreciated.

thanks in advance,

m@

when need display payment options, display hud, mbprogresshud block user using ui , start network call. when network call returns, dismiss hud in either in success/failure blocks or in delegate methods , refresh view data received.

if don't hud idea can display appropriate in ui, uilabel "loading..." or uiactivityindicatorview.

if need data display first thing, in viewdidappear; if happens on action move transition next view (performseguewithidentifier or whatever) network success block/callback , make network call when action called.

there should examples in networking library of how, or take @ usage sample code in mbprogresshud https://github.com/jdg/mbprogresshud.


Comments

Popular posts from this blog

php - Wordpress website dashboard page or post editor content is not showing but front end data is showing properly -

How to get the ip address of VM and use it to configure SSH connection dynamically in Ansible -

javascript - Get parameter of GET request -