performSelectorInOC 使用文档

问题

JavaScript 语言是单线程的,在 OC 使用 JavaScriptCore 引擎执行 JS 代码时,会对 JS 代码块加锁,保证同个 JSContext 下的 JS 代码都是顺序执行。所以使用 JSPatch 替换的方法都会在这个锁里执行,无法并行执行,这导致如果主线程和子线程同时运行了 JSPatch 替换的方法,子线程就会卡住主线程。

对此可以使用 .performSelectorInOC(selector, arguments, callback) 方法,在 JS 使用这个接口调用 OC 方法时,可以脱离 JavaScriptCore 的锁,在释放了 JavaScriptCore 锁后才在 OC 执行这个方法,这样这个方法就可以与其他线程的 JS 方法并行执行。

API

obj.performSelectorInOC(selector, arguments, callback)
@param selector: 调用的方法 selector 字符串
@param arguments: 方法参数,数组
@param callback: OC方法执行后的回调,第一个参数值为OC方法返回值 

obj 是执行主体,NSObject 对象。

范例

defineClass('JPClassA', {
  methodA: function() {
    //run in mainThread
  },
  methodB: function() {
      //run in childThread
      var limit = 20;
      var data = self.readData(limit);
      var count = data.count();
      return {data: data, count: count};
  }
})
上述例子中若在主线程和子线程同时调用  -methodA  和  -methodB ,而  -methodB  里  self.readData(limit)  这句调用耗时较长,就会卡住主线程方法  -methodA  的执行,对此可以让这个调用改用  .performSelectorInOC()  接口,让它在 JavaScriptCore 锁释放后再执行,不卡住其他线程的 JS 方法执行:

defineClass('JPClassA', {
  methodA: function() {
    //run in mainThread
  },
  methodB: function() {
      //run in childThread
      var limit = 20;
      return self.performSelectorInOC('readData', [limit], function(ret) {
          var count = ret.count();
          return {data: ret, count: count};
      });
  }
})
这时在 OC 执行 -methodB 的过程如下,加锁表示 JavaScriptCore 执行 JS 代码时加的锁:

加锁 -> 执行JS代码 (var limit = 20) -> 去锁 -> 调用 readData 方法 -> 加锁 -> 调用 callback -> 去锁

上述调用是同步的,上面两种写法的执行顺序和结果完全一样。

若需要多次使用 .performSelectorInOC() 接口,可以无限嵌套:

methodB: function() {
  var slf = self;
  return self.performSelectorInOC('readData', [limit], function(ret) {
      return slf.performSelectorInOC('methodC', [ret], function(methodCRet){
          return slf.performSelectorInOC('methodD', [], function(methodDRet){
              return methodDRet;
          })
      })
  });
}

死锁例子

此接口除了用于解决主线程卡顿问题,还可以用于解决因 JavaScriptCore 锁导致的死锁问题。下面举个死锁的例子:

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
    ClassA* obj = [[ClassA alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //A线程
        @synchronized(obj) {    //X锁
            sleep(3);
            [obj methodA];   //methodA被JS替换,调用会进JS,请求JSCore的锁
        }
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //B线程
        [obj methodA];  //methodA被JS替换,调用会进JS,请求JSCore的锁
    });
}
@end


@implementation ClassA
- (void)methodA
{
}
- (void)methodB
{
    @synchronized(self) {   //X锁
        int a = 0;
    }
}
@end

defineClass('ClassA', {
    methodA: function() {
        self.methodB()   //调用到OC,
    },
})

上述调用顺序:


A线程和B线程都在等待对方的锁释放,导致死锁。对此可以改成 performSelectorInOC 的方式调用解决死锁问题:

defineClass('ClassA', {
    methodA: function() {
        return self.performSelectorInOC('methodB', [], function(ret){});
    },
})
调用顺序和锁的关系就变成:


注意点

  1. 只能在 defineClass() 的方法里使用。
  2. 调用时必须 return,否则无法调用到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值