【玩转cocos2d-x之十九】从CCObject瞧cocos2d-x的拷贝机制

【玩转cocos2d-x之十九】从CCObject看cocos2d-x的拷贝机制

原创作品,转载请标明http://blog.csdn.net/jackystudio/article/details/13295505


CCObject在之前的文章中出现了N次,它扮演了一个老祖宗的角色,但是它到底是做什么的?先从它看看cocos2d-x的拷贝机制吧。


1.CCCopying

CCObject从CCCopying继承而来,而CCCopying拥有唯一的一个成员虚函数copyWithZone,这个函数可以认为是拷贝的一个协议,所有继承了CCObject并且需要实现拷贝功能的子类都可以通过它来实现,它的源码很简单,就是一个未实现的断言。CCZone是神马?只是封装了一个CCObject对象指针而已。

CCObject* CCCopying::copyWithZone(CCZone *pZone)
{
    CC_UNUSED_PARAM(pZone);
    CCAssert(0, "not implement");
    return 0;
}

2.CCObject的子类拷贝问题

再看看CCObject中copy的实现,是的,直接调用了copyWithZone,所以子类在处理拷贝问题时只需要对copyWithZone进行实现,使用时调用copy即可。

CCObject* CCObject::copy()
{
    return copyWithZone(0);
}

3.CCArray示例

这里以CCArray的拷贝为例,CCArray继承于CCObject,如上所说,我们只需要实现copyWithZone,然后在拷贝时调用copy即可实现CCArray的拷贝。


3.1.CCArray拷贝时调用copy

CCArray* CCArray::createWithArray(CCArray* otherArray)
{
    CCArray* pRet = (CCArray*)otherArray->copy();//copy调用了copyWithZone
    pRet->autorelease();
    return pRet;
}

3.2.copyWithZone的实现

可以看出CCArray采用的是深拷贝的方式。

CCObject* CCArray::copyWithZone(CCZone* pZone)
{
    CCAssert(pZone == NULL, "CCArray should not be inherited.");
    CCArray* pArray = new CCArray();  //new一个存放拷贝的空间
    pArray->initWithCapacity(this->data->num > 0 ? this->data->num : 1);//初始化一样的长度

    CCObject* pObj = NULL;
    CCObject* pTmpObj = NULL;
    CCARRAY_FOREACH(this, pObj)//遍历CCArray成员
    {
        pTmpObj = pObj->copy();//逐个拷贝
        pArray->addObject(pTmpObj);//添加到新拷贝pArray中
        pTmpObj->release();
    }
    return pArray;//返回拷贝
}

4.深拷贝和浅拷贝

其实不单是CCArray,cocos2d-x采用的都是深拷贝的方式,深拷贝和浅拷贝的概念和详解请移步http://blog.csdn.net/jackystudio/article/details/11553117。它们的区别在于当前对象是否包含了对其他资源的引用。在拷贝机制上采用深拷贝的方式,大大方便了我们对内存的管理,避免因资源的释放导致引用异常。这对于平时在进行一些自定义子类的拷贝处理上还是很有指导意义的。

1楼wind20061小时前
pTmpObj = pObj->copy();//逐个拷贝 n pArray->addObject(pTmpObj);//添加到新拷贝pArray中 n pTmpObj->release(); nn这三句话 pObj->copy() 创建 pTmpObj 是否需要retain? nn不然 pTmpObj->release(); 不是销毁了嘛
Re: jackyvincefu46分钟前
回复wind2006n其实你没注意到而已,我们平时最常用的addChild也是一样这么用的,为什么create出来的精灵在addChild之后就不会自动释放,因为addChild其实也是调用了上面的函数。。。内部进行retain了。
Re: jackyvincefu41分钟前
回复wind2006n需要retain,但不是我们来做,pArray->addObject(pTmpObj);调用了tnccArrayEnsureExtraCapacity(arr, 1);nccArrayAppendObject(arr, object);n前者用来保证有足够的空间,后者则用来追加对象。它的实现:nvoid ccArrayAppendObject(ccArray *arr, CCObject* object)n{n CCAssert(object != NULL, "Invalid parameter!");n object->retain();ntarr->arr[arr->num] = object;ntarr->num++;n}n这也就是再次调用release的目的。。。我也感觉这样设计好奇怪。。。