iOS从Javascript调用Objective-C:有些调用被忽略了吗?

时间:2012-05-15 21:41:50

标签: javascript objective-c ios timing

我已经实现了似乎是使用UIWebView委托shouldStartLoadWithRequest()方法在iOS上从javascript到objective-c进行通信的唯一方式。

一开始似乎工作正常,但现在我注意到如果我在短时间内从javascript到objective-c多次调用,通常会忽略第二个调用(应用程序是钢琴键盘,每个按键触发对本机代码的调用,在处理多个触摸时,本机代码不会为每个手指调用。

这是我的响应javascript调用的Objective-c代码。我知道这很狡猾,但我只是想要现在有用的东西。

- (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request 
        navigationType:(UIWebViewNavigationType)navigationType 
{  
  // Intercept custom location change, URL begins with "js-call:"
  NSString * requestString = [[request URL] absoluteString];
  if ([requestString hasPrefix:@"js-call:"]) 
  {
    // Extract the selector name from the URL
    NSArray * components = [requestString componentsSeparatedByString:@":"];
    NSString * functionCall = [components objectAtIndex:1];
    NSArray * params = [functionCall componentsSeparatedByString:@"%20"];
    NSString * functionName = [params objectAtIndex:0];

    // Parse playnote event
    if ([functionName isEqualToString:@"playNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [m_audioController playNote:[param intValue]];
      NSString * jscall = [NSString stringWithFormat:@"document.PlayNoteCallback(%i);", note_id];
      NSLog(@"playNote: %i", (int)note_id);
      [m_webView stringByEvaluatingJavaScriptFromString:jscall];
    }

    // Parse stopnote event
    if ([functionName isEqualToString:@"stopNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [param intValue];
      NSLog(@"stopNote: %i", (int)note_id); 
      [m_audioController stopNote:note_id];
    }

    // Parse log event
    if ([functionName isEqualToString:@"debugLog"])
    {
      NSString * str = [requestString stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
      NSLog(@"%s", [str cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
    }

    // Cancel the location change
    return NO;
  }

  // Accept this location change
  return YES;

}

从javascript我通过设置单个隐藏iframe的src属性来调用objective-c方法。这将触发objective-c中的委托方法,然后调用所需的本机代码。

$("#app_handle").attr("src", "js-call:playNote " + key.data("pitch"));

app_handle是有问题的iframe的ID。

总而言之,我的方法的基础工作,但在短时间内多次调用不起作用。这只是我们被迫从javascript到objective-c的可怕方法的神器吗?或者我做错了什么?我知道PhoneGap做了类似的事情来达到同样的目标。我宁愿不使用PhoneGap,所以如果他们没有遇到这个问题,那么我很想知道他们正在做些什么来使这项工作。

更新

我刚发现:send a notification from javascript in UIWebView to ObjectiveC 这证实了我对快速接连的电话迷路的怀疑。显然我需要将我的呼叫混为一谈或手动延迟呼叫,以便在我再次呼叫时返回url请求。

2 个答案:

答案 0 :(得分:4)

接受的答案无法解决问题,因为仍会忽略在处理第一个之前到达的位置更改。请参阅第一条评论。

我建议采用以下方法:

function execute(url) 
{
  var iframe = document.createElement("IFRAME");
  iframe.setAttribute("src", url);
  document.documentElement.appendChild(iframe);
  iframe.parentNode.removeChild(iframe);
  iframe = null;
}

您重复调用execute函数,因为每个调用都在自己的iframe中执行,所以在快速调用时不应忽略它们。

this guy的信用。

答案 1 :(得分:1)

不是在JavaScript端对所有内容进行排队,而是使用GCD将复杂逻辑(如对音频处理程序的调用)移出主线程可能更容易,更快捷。您可以使用dispatch_async()对事件进行排队。如果你将它们放入一个串行队列,那么它们肯定会按顺序运行,但你会更快地回到javascript。例如:

  • 在初始化期间为对象创建队列:

    self.queue = dispatch_queue_create(“player”,NULL);

  • 在你的回调中:

    if ([functionName isEqualToString:@"stopNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [param intValue];
      NSLog(@"stopNote: %i", (int)note_id); 
      dispatch_async(self.queue, ^{[m_audioController stopNote:note_id]});
    }