Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

怎么定义含block参数的方法 #155

Closed
wonderffee opened this issue Nov 26, 2015 · 11 comments
Closed

怎么定义含block参数的方法 #155

wonderffee opened this issue Nov 26, 2015 · 11 comments

Comments

@wonderffee
Copy link

比如OC代码:

@implementation NetAPIClient
- (void)requestInfoWithObj:(NSMutableDictionary*)dictParameters andBlock:(void (^)(id data, NSError *error))block{
    [[NetAPIClient sharedJsonClient] requestJsonDataWithPath:@"index.php" withParams:dictParameters withMethodType:Get andBlock:^(id data, NSError *error) {
        if (data) {            
            block(data, nil);
        }
    }];
}
@end

使用JSPatchConvertor转换大概是下面的形式:

require('NetAPIClient');
defineClass('NetAPIClient', {
    requestInfoWithObj_andBlock: function(dictParameters, blockCallback) {
        NetAPIClient.sharedJsonClient().requestJsonDataWithPath_withParams_withMethodType_andBlock("index.php()", dictParameters, 1, block('id,NSError*', function(data, error) {
                blockCallback(data, null);
            }
        }));
},
});

blockCallback这个地方的定义肯定是有问题的,Xcode运行直接crash,报错:TypeError: blockCallback is not a function. (In 'blockCallback(data, null)', 'blockCallback' is an instance of Object)

Wiki里提供的好像都是调用Block的示例,对于一个方法中带block参数的,如何进行定义与调用,应该没有,求指点

@bang590
Copy link
Owner

bang590 commented Nov 26, 2015

是在OC调 -requestInfoWithObj:andBlock: 这个方法吗?贴上来看看

@wonderffee
Copy link
Author

requestInfoWithObj这个方法也是在JS里面调用的,代码我简化了许多

@wonderffee
Copy link
Author

来个更简单的例子,

- (void)callBlock:(void(^)(NSString *str))block
{
    block(@"test block");
}

- (void)runBlock{
    [self callBlock:^(NSString *str) {
        NSLog(@"%@", str);
    }];
}

这里面的两个函数并不一定在同一个类的。把上面的代码翻译为JS代码,大概是:

callBlock: function(blk) {
    blk("test block");
},
runBlock: function() {
    self.callBlock(block('NSString*', function(str) {
        console.log(str);
    }));
},

然后在js里调用runBlock,即self.runBlock(); 运行就Crash报错:msg: '[object Object]' is not a function (evaluating 'blk("test block")'),错误跟这个issue几乎一样:#122
但是我并不是十分明白它的解决方法

我想的是作为callBlock的block参数blk应该不是这样简简单单定义吧,到底应该怎么定义才能让上面的js代码正常运行起来呢?

@bang590
Copy link
Owner

bang590 commented Nov 28, 2015

这个定义跟用法都没有错,单纯把 block 传给 OC 调用或 OC 传给 JS 调用都是没问题的, 但目前不支持 JS 封装的 block 传到 OC 再传回 JS 去调用。

原因是:在 JS 用 block() 封装传到 OC 时,根据 这里的代码 生成的 block 参数类型是 void*,这个 block 再传回 JS 时 JavaScriptCore 不认带这种参数类型的 block,所以无法调用。

简单模拟 block 不同参数类型传到 JS 的效果:

//JS:
callBlock: function(blk) {
    blk("test block");
},
///OC
- (void)runBlock{
    id cb = ^void(void *p0) {
        id str = (__bridge id)p0;
        NSLog(@"%@", str);
    };
    id cbStr = ^void(NSString *str) {
        NSLog(@"%@", str);
    };
    [self callBlock:cbStr]; //it's OK
    [self callBlock:cb];    //it's not OK
}

未找到解决方法 :(

@wonderffee
Copy link
Author

//JS:
callBlock: function(blk) {
    blk("test block");
},

我感觉上面的代码的主要问题是JS不知道blk的实际类型,因为不知道所以就像你说的用void*类型代替,然后JS认为它是一个普通对象,而非block对象(function)。而它对应的OC代码是从参数就知道是什么类型的。

我想同样的问题应该是存在于OC的。如果把该函数对应的OC方法定义从- (void)callBlock:(void(^)(NSString str))blk修改为- (void)callBlock:(void)blk,函数体内的blk(@"test block");编译就会报错,因为认为它是对象,not a function。

但是在OC内,如果把blk强制转换成block形式,就没问题了,代码如下:

- (void)callBlock:(void *)blk
{
    void (^asBlock)(NSString*) = (__bridge typeof(asBlock)) blk;
    asBlock(@"test block");
}

如果这个道理没错的话,我觉得要解决上面的问题,关键在于如何在js中对blk进行强制类型转换

@bang590
Copy link
Owner

bang590 commented Nov 30, 2015

你没理解我之前的解释,也没理解真正的原因。JS 知道 blk 的类型就是 block,JavaScriptCore 会自动把 block 转为 JS Function,这里没法转是因为这里传过来的 block 里的参数类型含有 void*(!!!注意是block里的参数类型,不是 block 本身!!!),JavaScriptCore 不认这种参数类型,没法把它转为 JS Function。至于为什么这里 block 的参数类型会是 void* 上一篇已经给出源码链接。

@wonderffee
Copy link
Author

知道你的意思了,可是我单步调试了一下,genCallbackBlock这个函数好像根本没有调用到啊

@CodeLife2012
Copy link

@bang590 为什么需要声明为void *呢?

@liuyanhongwl
Copy link

liuyanhongwl commented Aug 22, 2016

如果block不加参数可以解决吗?

还是block有什么隐藏参数也加成了void * 类型吗?

@bang590

@JeryCG
Copy link

JeryCG commented Feb 15, 2017

@bang590 你好, 测试了下文档中代码
发觉加了require('JPEngine').addExtensions(['JPBlock']);
文档中的代码依旧会crash
msg: blk is not a function. (In 'blk("test block")', 'blk' is an instance of Object)

@leixiang1986
Copy link

这就是为什么现在的版本不支持masonry的原因吗?用masonry报:TypeError: undefined is not an object (evaluating 'make.__c')。
很早以前的版本是支持的,最新的版本不支持了,调试了,没找到原因。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants