JSPatch icon indicating copy to clipboard operation
JSPatch copied to clipboard

NSMutableArray在返回时会被转换成NSArray

Open nicaicaicaicai opened this issue 8 years ago • 11 comments

你好,NSMutableArray在返回时会被转换成NSArray,我们的项目在其它地方用的NSMutableArray结束的参数,导致这样的传参会崩溃,请问怎么解决? qq20161110-0

nicaicaicaicai avatar Nov 10 '16 02:11 nicaicaicaicai

NSMutableArray不会被转换成NSArray。

bang590 avatar Nov 11 '16 07:11 bang590

这是我们的OC代码 qq20161111-0

下面是我们写的JS代码: qq20161111-1

下面是报错信息: image 报错在了这个地方finished(customProcessArray, firmProcessArray, response, error); 请问是什么原因呢?谢谢

nicaicaicaicai avatar Nov 11 '16 07:11 nicaicaicaicai

@bang590 请问是什么原因呢?该如何该呢?

nicaicaicaicai avatar Nov 11 '16 08:11 nicaicaicaicai

image 你不是自己把它变成NSArray了吗

bang590 avatar Nov 11 '16 08:11 bang590

我这么写他也会报错: var customProcessArray = NSMutableArray.alloc().init(); var firmProcessArray = NSMutableArray.alloc().init(); @bang590 ,这是为什么啊?

nicaicaicaicai avatar Nov 11 '16 11:11 nicaicaicaicai

看不出问题,你这么写在OC断点看到传过去是什么对象?

bang590 avatar Nov 11 '16 12:11 bang590

@bang590 接着@PWDream的提问: 1、 这是NSMutableArray不是NSArray 2、还没回传到OC就报错了所以在OC中断不到 image是在js中的这步报的错

Toge66 avatar Nov 15 '16 08:11 Toge66

可以简化成一个demo工程发来看看吗

bang590 avatar Nov 15 '16 10:11 bang590

@bang590 写了个小demo没有报错但是使用可变数组(NSMutableArray)作为block的参数没有回调成功,使用不可变数组(NSArray)作为block的参数就可以回调成功 下面是代码

OC代码

- (void)setupView {
    self.view.backgroundColor = [UIColor redColor];

    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    button1.frame = CGRectMake(100, 200, 100, 50);
    [button1 setTitle:@"button1" forState:UIControlStateNormal];
    [button1 setBackgroundColor:[UIColor greenColor]];
    [button1 addTarget:self action:@selector(buttonAction1) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button1];

    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
    button2.frame = CGRectMake(100, 300, 100, 50);
    [button2 setTitle:@"button2" forState:UIControlStateNormal];
    [button2 setBackgroundColor:[UIColor purpleColor]];
    [button2 addTarget:self action:@selector(buttonAction2) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button2];
}

- (void)buttonAction1 {
    [self getData1:^(NSArray *result1, NSArray *result2) {
        NSLog(@"%s",__FUNCTION__);
        NSLog(@"%@\n=========================\n%@",result1,result2);
    }];
}

- (void)getData1:(void(^)(NSArray *result1,NSArray *result2))finished {
    NSMutableArray *result = [NSMutableArray array];
    for (int i = 0; i < 5; i ++) {
        [result addObject:@"aa"];
    }
    finished ? finished(result,result) : nil;
}

- (void)buttonAction2 {
    [self getData2:^(NSMutableArray *result1, NSMutableArray *result2) {
        NSLog(@"%s",__FUNCTION__);
        NSLog(@"%@\n=========================\n%@",result1,result2);
    }];
}

- (void)getData2:(void(^)(NSMutableArray *result1,NSMutableArray *result2))finished {
    NSMutableArray *result = [NSMutableArray array];
    for (int i = 0; i < 5; i ++) {
        [result addObject:@"bb"];
    }
    finished ? finished(result,result) : nil;
}

JS代码

require('NSMutableArray');
defineClass('JSPathTestViewController',{
  getData1: function(finished) {
      var result = NSMutableArray.array();
      for (var i = 0; i < 5; i++) {
          result.addObject('aa');
      }
      if (finished) {
        finished(result, result)
      }
  },
  getData2: function(finished) {
      var result = NSMutableArray.array();
      for (var i = 0; i < 5; i++) {
          result.addObject('bb');
      }
      if (finished) {
        finished(result, result)
      }
  }
})

Toge66 avatar Nov 16 '16 04:11 Toge66

明白了

  1. OC 通过 JavaScriptCore 跟 JS 通信,若 OC 返回 NSMutableArray 到 JS,会被自动转成 JS 的 Array 类型。
  2. JS 的 Array 类型传到 OC 会自动转为 NSArray 类型。
  3. 方法调用里 NSMutableArray 没有这个转换问题是因为 JSPatch 用 JPBoxing 装箱的方式封装了。
  4. 一个 block 通过 JavaScriptCore 从 OC 传到 JS 会自动转为 JS Function 类型,可以直接调用这个 Function。
  5. JSPatch 在调用这个 Function (finished) 之前会把参数通过 OC 里的 formatJSToOC 方法转换,主要是处理 JPBoxing 拆箱,NSMutableArray 在这里被转为 JS Array 类型,再传入这个block进入OC就会变成 NSArray。
  6. 若要解决这个问题,就不能让 block 传到 JS 时自动转为 function,要通过类似 JPBoxing 装箱的方式传到 JS,调用时再回到 OC 调用。但在 OC 调用时不知道这个 block 的参数类型和参数个数,无法进行调用,暂时没想到方法解决。

bang590 avatar Nov 16 '16 11:11 bang590

明白了,thx

Toge66 avatar Nov 16 '16 12:11 Toge66