Skip to content

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

Closed
@wonderffee

Description

@wonderffee

比如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参数的,如何进行定义与调用,应该没有,求指点

Activity

bang590

bang590 commented on Nov 26, 2015

@bang590
Owner

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

wonderffee

wonderffee commented on Nov 26, 2015

@wonderffee
Author

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

wonderffee

wonderffee commented on Nov 27, 2015

@wonderffee
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

bang590 commented on Nov 28, 2015

@bang590
Owner

这个定义跟用法都没有错,单纯把 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

wonderffee commented on Nov 29, 2015

@wonderffee
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

bang590 commented on Nov 30, 2015

@bang590
Owner

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

wonderffee

wonderffee commented on Nov 30, 2015

@wonderffee
Author

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

CodeLife2012

CodeLife2012 commented on May 19, 2016

@CodeLife2012

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

liuyanhongwl

liuyanhongwl commented on Aug 22, 2016

@liuyanhongwl

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

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

@bang590

JeryCG

JeryCG commented on Feb 15, 2017

@JeryCG

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

leixiang1986

leixiang1986 commented on Dec 8, 2022

@leixiang1986

这就是为什么现在的版本不支持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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @bang590@CodeLife2012@wonderffee@leixiang1986@JeryCG

        Issue actions

          怎么定义含block参数的方法 · Issue #155 · bang590/JSPatch