什么是iOS的(或RubyMotion)成语等待异步执行的块? [英] What is the iOS (or RubyMotion) idiom for waiting on a block that executes asynchronously?

查看:143
本文介绍了什么是iOS的(或RubyMotion)成语等待异步执行的块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在拉我的头发数周对这个问题耍赖,我只是无法找到怎样还是怎样做任何信息或提示,所以我在这里希望有人在RubyMotion论坛能帮助我。

I have been pulling my hair out for weeks on this niggling problem, and I just can't find any info or tips on how or what to do, so I'm hoping someone here on the RubyMotion forums can help me out.

道歉提前如果这是一个有点长,但它需要一些设置才能正常解释的问题。作为背景,我有一个使用JSON / REST后端实现伊纳Rails应用程序的应用程序。这是pretty简单的东西。后端工作正常,并在一定程度上,所以是前端。我可以拨打电话来填充RubyMotion客户端模型对象,一切是伟大的。

Apologies in advance if this is a little long, but it requires some setup to properly explain the issues. As background, I've got an app that uses a JSON/REST back-end implemented ina Rails app. This is pretty straightforward stuff. The back-end is working fine, and up to a point, so is the front end. I can make calls to populate model objects in the RubyMotion client and everything is great.

的一个问题是,所有的HTTP / JSON库处理请求时使用异步调用。这是好的,我明白他们为什么这样做,但有一对夫妇在那里我需要能够等待通话,因为我需要在进行下一步之前做返回的结果的东西的情况。

The one issue is that all of the http/json libs use async calls when processing requests. This is fine, and I understand why they are doing it, but there are a couple of situations where I need to be able to wait on a call because I need to do something with the returned results before proceeding to the next step.

考虑这样一个用户想要进行付款的例子,它们具有一些储存的付款信息。此前presenting用户提供的支付选项的列表,我想确保我在客户端的最新名单。所以,我需要给用户对象,将抓住当前的列表(或超时)的方法的请求。但我不想继续下去,直到我肯定列表或者是电流或调用后端失败。基本上,我想这个调用块(不阻塞UI),直到返回结果。

Consider the example where a user wants to make a payment, and they have some saved payment information. Prior to presenting the user with a list of payment options, I want to make sure that I have the latest list at the client. So I need to make a request to a method on the user object that will grab the current list (or timeout). But I don't want to continue until I am sure that the list is either current, or the call to the back-end has failed. Basically, I want this call to block (without blocking the UI) until the results are returned.

替代诸如轮询更改或从后端到前推的变化不适合这种情况。我也算是简单地从目标表单把数据(而不是推入形式),而是因为我想做这取决于用户是否具有零,一个或多个付款方式不同的东西,这并不在这个特殊的情况下工作保存。所以,我需要知道提前推到下一个控制器,并提前就知道了,我需要做一个同步调用。

Alternatives such as polling for changes or pushing changes from the back-end to the front are not appropriate for this scenario. I also considered simply pulling the data from the destination form (rather than pushing it into the form) but that doesn't work in this particular scenario because I want to do different things depending on whether the user has zero, one or multiple payment options saved. So I need to know in advance of pushing to the next controller, and to know in advance, I need to make a synchronous call.

我的第一次进攻是要建立一个共享实例(让我们把它叫做SyncHelper),我可以用它来存储请求返回的结果,与完成状态一起。它可以提供只是旋转使用CFRunLoopRunInMode任直到请求完成,或者直到该请求超时的等待方法。

My first attack was to create a shared instance (let's call it the SyncHelper) that I can use to store the returned result of the request, along with the "finish" state. It can provide a wait method that just spins using CFRunLoopRunInMode either until the request is finished, or until the request times out.

SyncHelper看起来有点像这样(我已经编辑它采取一些无关痛痒的东西了):

SyncHelper looks a bit like this (I've edited it to take some 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 for API: #{@error}" if !error?
    end
  end
end

然后,我有一个辅助方法是这样,这将允许我通过规定的syncr实例被调用的方法进行任何调用同步的。

Then I have a helper method like this, which would allow to me to make any call synchronous via the provision of the syncr instance to the invoked method.

def ApiHelper.make_sync(&block)
  syncr = ApiHelper::SyncHelper.new
  BubbleWrap::Reactor.schedule do
    block.call syncr
  end
  syncr.wait
  syncr.result
end

我所希望做的是到处使用异步版本,但在少数地方,我需要同步做一些事情的情况下,我只想环绕这样的make_sync块调用:

What I had hoped to do was use the async versions everywhere, but in the small number of cases where I needed to do something synchronously, I would simply wrap the call around a make_sync block like this:

# This happens async and I don't care
user.async_call(...)
result = ApiHelper.make_sync do |syncr|
  # This one is async by default, but I need to wait for completion
  user.other_async_call(...) do |result|
    syncr.finish_with_result(result)
  end
end
# Do something with result (after checking for errors, etc)
result.do_something(...)

重要的是,我希望能够得到从同步回调到调用上下文中的返回值,因此'结果= ...'位。如果我不能做到这一点,那么整个事情是没多大用,我反正。通过传递syncr,我可以给它一个finish_with_result打电话告诉任何人聆听了异步任务已经完成,并通过调用消费有存储结果。

Importantly, I want to be able to get the return value from the 'synchronised' call back into the invoking context, hence the 'result =...' bit. If I can't do that, then the whole thing isn't much use to me anyway. By passing in syncr, I can make a a call to its finish_with_result to tell anyone listening that the async task has completed, and store the result there for consumption by the invoker.

我make_sync和SyncHelper实现因为他们的立场(除了显而易见的事实,我可能做一些愚蠢的深刻)的问题是,气泡布:: Reactor.schedule里面的code做...结束块不会被调用,直到调用syncr.wait超时后(注:没有完成,因为该块永远不会跑的机会,因此不能存储导致它)。这是完全访问CPU挨饿所有其它进程,即使寿调用CFRunLoopRunInMode在里面等待发生。我是IM pression的CFRunLoopRunInMode在这个配置将要分离的等待,但允许其他排队块下运行,但现在看来,我已经得到了错误的。

The problem with my make_sync and SyncHelper implementations as they stand (apart from the obvious fact that I'm probably doing something profoundly stupid) is that the code inside the BubbleWrap::Reactor.schedule do ... end block doesn't get called until after the call to syncr.wait has timed out (note: not finished, because the block never gets the chance to run, and hence can't store result in it). It is completely starving all other processes from access to the CPU, even tho the call to CFRunLoopRunInMode is happening inside wait. I was under the impression that CFRunLoopRunInMode in this config would spin wait, but allow other queued blocks to run, but it appears that I've got that wrong.

这令我的东西,人们需要从时间到时间做的,所以我不能有这个类型的问题烦恼的唯一的人。

This strikes me as something that people would need to do from time-to-time, so I can't be the only person having trouble with this kind of problem.

有我有太多疯狂的药丸?有没有一个标准的iOS成语做这一点,我只是不理解?有没有更好的方法来解决这样的问题?

Have I had too many crazy pills? Is there a standard iOS idiom for doing this that I'm just not understanding? Is there a better way to solve this kind of problem?

任何帮助将是非常美联社preciated。

Any help would be much appreciated.

由于提前,

米@

推荐答案

当你需要显示的付款选项,显示HUD,像MBProgressHUD从使用UI阻止用户,然后开始你的网络电话。当网络调用返回,驳回HUD中无论是在你的成功/失败块或委托方法,然后刷新的数据视图接收。

When you need to display the payment options, display a HUD, like MBProgressHUD to block the user from using the UI and then start your network call. When the network call returns, dismiss the HUD in either in your success/failure blocks or in the delegate methods and then refresh your view with the data received.

如果你不喜欢的HUD想法你可以在你的UI显示相应的东西,像一个UILabel载入中...或UIActivityIndi​​catorView。

If you don't like the HUD idea you can display something appropriate in your UI, like a UILabel with "loading..." or an UIActivityIndicatorView.

如果你需要得到的数据显示第一件事情,做在viewDidAppear;如果它发生在一个动作然后移动过渡到下一个视图(无论performSegueWithIdentifier或)进入您的网络的成功块/回调,使网络调用时的动作被调用。

If you need to get the data to display first thing, do it in viewDidAppear; if it happens on an action then move your transition to the next view (performSegueWithIdentifier or whatever) into your network success block/callback and make the network call when the action is called.

应该有怎样的网络库的例子,或者看看在MBProgressHUD本身的 https://github.com/jdg/MBProgressHUD

There should be examples in your networking library of how, or take a look at the usage sample code in MBProgressHUD itself https://github.com/jdg/MBProgressHUD.

这篇关于什么是iOS的(或RubyMotion)成语等待异步执行的块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆