Iterating through cc.Node children breaks on v2.1.4

We updated from cocos2dx 2.1.3 to 2.1.4 and are running into some problems iterating over CCNode children. The problem is with this commit: https://github.com/cocos2d/cocos2d-x/commit/2f4a0ed37c6686a521a32c8301d48751288d3292.

On line 90, you add the JSB_ScrollViewDelegate as a child in js_cocos2dx_CCScrollView_setDelegate(). If you iterate through all of the child nodes in JS, it hits the assert in ccarray_to_jsval(). I’m not sure why the JSB_ScrollViewDelegate is failing the proxy check at the beginning:

js_proxy_t* jsproxy = js_get_or_create_proxy(cx, obj);
if (jsproxy) {
     arrElement = OBJECT_TO_JSVAL(jsproxy->obj);
}

Am I forgetting to include some files in my project? Or is this a potential bug?

Thanks,

— Joel

Hey, @Joel Poloney,
How did you iterate through all of children nodes in JS?

`James It seems that getChilden() automatically refer by engine:

JSBool js_cocos2dx_CCNode_getChildren(JSContext *cx, uint32_t argc, jsval vp)
{

if (argc == 0) {
cocos2d::CCArray
ret = cobj->getChildren();
jsval jsret;
jsret = ccarray_to_jsval(cx, ret);
JS_SET_RVAL(cx, vp, jsret);
return JS_TRUE;
}

}

This probleam cause by a JSB_ScrollViewDelegate being added to a CCScrollView.m_pContainer, but

js_proxy_t* jsproxy = js_get_or_create_proxycocos2d::CCObject(cx, obj);

couldnot recognize the JSB_ScrollViewDelegate in

jsval ccarray_to_jsval(JSContext* cx, CCArray *arr)

James Chen wrote:

Hey, `Joel Poloney,
How did you iterate through all of children nodes in JS?

Yep, Mutoo Lau is correct. That’s where we’re seeing the error too.

— Joel

I didn’t find a good way to delete instance that created by new JSB_ScrollViewDelegate.
Since CCScrollView::setDelegate is a weak reference function, I don’t know when the JSB_ScrollViewDelegate needs to be deleted.
Therefore, I added it to the CCScrollView and make JSB_ScrollViewDelegate inherited from CCNode.
Then, JSB_ScrollViewDelegate will get notification when its parent is onExit.
I didn’t find a better way to resolve this issue.

Any suggestion or solution will be appreciated. Thanks.

@James Chen - JSB_ScrollViewDelegate is a CCNode, right? Shouldn’t the proxy be resolving the object correctly?

js_proxy_t* jsproxy = js_get_or_create_proxy(cx, obj);
if (jsproxy) {
     arrElement = OBJECT_TO_JSVAL(jsproxy->obj);
}

That’s what I think was intended, but it doesn’t appear to actually be working. Thoughts?

@joel Poloney,
I found a solution to resolve this issue:

  1. Make JSB_ScrollViewDelegate to inherit from CCObject rather than CCNode.
  2. Use cobj->setUserObject* rather thanaddChild*.

Could you please try and give me the feedback?
Please make sure that the destructor of JSB_ScrollViewDelegate is invoked. Sorry for this issue.

`James Chen

What do you mean by invoking the destructor of JSB_ScrollViewDelegate? If I make these two changes, I’m getting compile errors on `oldDelegate->removeFromParent();@

If I comment that line out, it appears to work fine.

oldDelegate->removeFromParent();

Use cobj->setUserObject; instead.

What do you mean by invoking the destructor of JSB_ScrollViewDelegate?

I means that you should make a break point in the destructor of JSB_ScrollViewDelegate to ensure that it was invoked.

Yep, that appears to work. Should I make the same changes to CCTableView and CCEditBox as well?

I think so, the same problems occur to CCTableView (JSB_TableViewDataSource also);

Joel Poloney wrote:

Yep, that appears to work. Should I make the same changes to CCTableView and CCEditBox as well?

Yes, the binding of CCTableView, CCEditBox also need to be updated.
@Joel Poloney
Was the destructor of JSB_ScrollViewDelegate invoked?

Mutoo Lau wrote:

I think so, the same problems occur to CCTableView (JSB_TableViewDataSource also);
>
Joel Poloney wrote:
> Yep, that appears to work. Should I make the same changes to CCTableView and CCEditBox as well?

James Chen wrote:

@Joel Poloney
Was the destructor of JSB_ScrollViewDelegate invoked?
>

We only ever set the delegate once, so there’s no old delegate to remove. So, I added the same delegate again in our JS (called setDelegate twice in a row) and it went through to the destructor just fine.

Yes, cobj->setUserObject(NULL); is not needed indeed. Glad to hear that it works now. :slight_smile:

Joel Poloney wrote:

James Chen wrote:
> @Joel Poloney
> Was the destructor of JSB_ScrollViewDelegate invoked?
>
>
We only ever set the delegate once, so there’s no old delegate to remove. So, I added the same delegate again in our JS (called setDelegate twice in a row) and it went through to the destructor just fine.

I tried this solution for JSB_TableViewDataSource but failed;

I think it’s because of a CCTableView may need a JSB_TableViewDelegate and a JSB_TableViewDataSource but cobj~~>setUserObject just keeps one;
James Chen wrote:

Yes, cobj~~>setUserObject(NULL); is not needed indeed. Glad to hear that it works now. :slight_smile:
>
Joel Poloney wrote:
> James Chen wrote:
> > @Joel Poloney
> > Was the destructor of JSB_ScrollViewDelegate invoked?
> >
>
> We only ever set the delegate once, so there’s no old delegate to remove. So, I added the same delegate again in our JS (called setDelegate twice in a row) and it went through to the destructor just fine.

Yes, it’s a problem…… :frowning: No thoughts about that now….

Mutoo Lau wrote:

I tried this solution for JSB_TableViewDataSource but failed;
>
I think it’s because of a CCTableView may need a JSB_TableViewDelegate and a JSB_TableViewDataSource but cobj~~>setUserObject just keeps one;
>
James Chen wrote:
> Yes, cobj~~>setUserObject(NULL); is not needed indeed. Glad to hear that it works now. :slight_smile:
>
> Joel Poloney wrote:
> > James Chen wrote:
> > > @Joel Poloney
> > > Was the destructor of JSB_ScrollViewDelegate invoked?
> > >
> >
> > We only ever set the delegate once, so there’s no old delegate to remove. So, I added the same delegate again in our JS (called setDelegate twice in a row) and it went through to the destructor just fine.

Hey, I think you could create a CCArray, and set the CCArray to setUserObject. That’ll be able to work. :slight_smile:

It would not be a good idea…

JSB_TableViewDelegate and JSB_TableViewDataSource aren’t in the same place to be added into CCTableView;

James Chen wrote:

Hey, I think you could create a CCArray, and set the CCArray to setUserObject. That’ll be able to work. :slight_smile:

No good idea now. :frowning:

Mutoo Lau wrote:

It would not be a good idea…
>
JSB_TableViewDelegate and JSB_TableViewDataSource aren’t in the same place to be added into CCTableView;
>
James Chen wrote:
> Hey, I think you could create a CCArray, and set the CCArray to setUserObject. That’ll be able to work. :slight_smile:

Issue #2315 was created.