工厂方法:工厂方法是程序设计中一个经典的设计模式,指的是基类中只定义创建对象的接口,将实际的实现推迟到子类中。泛指一切生成并返回一个对象的静态函数。
例如:
CCObject * factoryMethod() {
CCObject *ret = new CCObject();
//在这里对ret对象进行必要的初始化操作
return ret;
}
这段代码中没有释放对ret的引用,会造成内存泄露的隐患。但是,如果在函数返回前就执行release(),这显然是不合适的,因为这会触发对象的回收,再返回的对象指针就成为了错误指针。autorelease()方法很好的解决了这个问题。此函数结束时我们已经丧失了对ret的引用,为了把ret对象传递给接受者,需要对它进行一次autorelease操作,虽然我们调用了autorelease方法,但是对象直到自动回收池释放之前是不会被真正释放掉的(通常Cocos2d-x会在每一帧之间释放一次自动回收池),调用者有足够的时间对它进行retain操作以便接管ret对象的引用权。因此Cocos2d-x的执行机制很巧妙地保证了回收池中的对象不会再使用完毕前释放。利用autorelease()修改后的工厂方法如下
CCObject * factoryMethod() {
CCObject *ret = new CCObject();
//在这里对ret对象进行必要的初始化操作
ret->autorelease();
return ret;
}
将一个对象赋值给某一指针作为引用的时候,为了遵循内存管理的原则,我们需要获得新对象的引用权,释放就对象的引用权。
例:
void SomeClass::setObject(CCObject *other) {
this->object->release();
other->retain();
this->object = other;
}
这里存在的隐患是,当other和object实际上指向同一个对象时,第一个release()可能会触发该对象的回收。所以应该先执行retain()来保证other对象有效,然后在释放旧对象。
void SomeClass::setObject(CCObject *other){
other->retain();
this->object->release();
this->object = other;
}
过多不必要的autorelease()将导致垃圾池臃肿膨胀,在存在大量内存操作的程序中会尤为严重地挤占本来就紧张的系统资源。且autorelease()只有在自动释放池被释放时才会进行一次释放操作,如果对象释放的次数超过了应有的次数,则这个错误在调用autorelease()时并不会被发现,只有当自动释放池被释放时(通常也就是游戏的每一帧结束时),游戏才会崩溃。在这种情况下,定位错误就变得十分困难。因此应该避免滥用autorelease(),只在工厂方法等不得不用的情况下使用,尽量以release()来释放对象引用.
相关辅助宏
CC_SAFE_DELETE(p) :使用delete操作符删除一个c++对象p,如果p为NULL,则不进行操作
CC_SAFE_DELETE_ARRAY(p):使用delete[]操作符删除一个C++数组p,如果p为NULL,则不进行操作
CC_SAFE_FREE(p):使用free()函数删除p,如果p为NULL,则不进行操作
CC_SAFE_RELEASE(p):使用release()方法释放cocos2d-x对象p的一次引用,如果p为NULL,则不进行操作
CC_SAFE_RELEASE_NULL(p):使用release()方法释放Cocos2d-x对象p的一次引用,再把p赋值为NULL。如果p已经为NULL,则不进行操作
CC_SAFE_RETAIN(p):使用reatin()方法增加Cocos2d-x对象p的一次引用。如果p为NULL,则不进行操作