ios retainn和release倒底怎么玩

2940人阅读
Object-C/Iphone(17)
& & & & &&在object-c中,系统自动会为每个创建的对象保存一个引用计数器。当对象被创建时,引用计数设置为1,每一次必须保持该对象时,需要发送(即调用)retain来使得引用计数加1。不再需要对象时,可以发送release消息,使得引用计数减1。当引用计数为0的时候,系统就会释放它的内存(通过向对象发送dealloc消息,也就是真正地去回收对象的内存)。另外,可以用retainCount来得到这个对象的引用计数,返回的类型是NSUInteger整数。基本的调用方式如下:
[obj retain];
[obj release];
[obj retainCount];&
1. 例子代码:
//1. ClassA.h
#import &Foundation/NSObject.h&
@interface ClassA: NSObject&
//2. ClassA.m
#import &ClassA.h&
@implementation ClassA
//在.h中有声明,不必声明dealloc方法
-(void) dealloc {
& & printf( &Deallocing ClassA\n& );
& & [super dealloc];
//3. main.m
#import &stdio.h&
#import &ClassA.h&
int main( int argc, const char *argv[] ) {
& & printf(&test case 1:\n&);
& & ClassA *a1 = [[ClassA alloc] init];
& & ClassA *a2 = [[ClassA alloc] init];
& & printf( &a1 retain count: %i\n&, [a1 retainCount] );
& & printf( &a2 retain count: %i\n&, [a2 retainCount] );
& & printf(&test case 2:\n&);
& & [a1 retain]; // 2
& & [a1 retain]; // 3
& & [a2 retain]; // 2
& & printf( &a1 retain count: %i\n&, [a1 retainCount] );
& & printf( &a2 retain count: %i\n&, [a2 retainCount] );
& & printf(&test case 3:\n&);
& & [a1 release]; // 2
& & [a2 release]; // 1
& & printf( &a1 retain count: %i\n&, [a1 retainCount] );
& & printf( &a2 retain count: %i\n&, [a2 retainCount] );
& & // release
& & [a1 release]; // 1 &//这里要注意,有几个retain,就要有几个release.
& & [a1 release]; // 0 &//而且,只调用一次delloc
& & [a2 release]; // 0
& & return 0;
2. 编译运行:
gcc -fconstant-string-class=NSConstantString -c main.m -I /GNUstep/System/Library/Headers
gcc -c ClassA.m -I /GNUstep/System/Library/Headers
gcc main.o ClassA.o -o main -L /GNUstep/System/Library/Libraries/ -lobjc -lgnustep-base
$ ./main.exe
test case 1:
a1 retain count: 1
a2 retain count: 1
test case 2:
a1 retain count: 3
a2 retain count: 2
test case 3:
a1 retain count: 2
a2 retain count: 1
Deallocing ClassA
Deallocing ClassA
& (1). 有几个retain,就要有几个release, 而且,delloc只会被调用一次;&
& (2). 一个原则是,是你自己申请的内存,就得由你来负责释放它;而不是你申请的,请不要随意去释放它,这不是你的责任;&
& (3). 每次retain对象时,应该release或autoreleas它。&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2488113次
积分:19642
积分:19642
排名:第397名
原创:364篇
转载:67篇
评论:309条
文章:18篇
阅读:30101
阅读:23901
(7)(2)(1)(1)(2)(7)(4)(1)(1)(2)(3)(1)(1)(1)(6)(4)(5)(4)(9)(10)(15)(3)(3)(4)(7)(11)(19)(5)(3)(3)(25)(15)(21)(4)(5)(11)(1)(8)(3)(3)(4)(7)(7)(1)(5)(6)(11)(7)(7)(4)(1)(3)(2)(2)(2)(2)(2)(1)(4)(14)(2)(20)(10)(13)(4)(7)(8)(8)(41)(1)(10)当前位置: →
→ cocos2d-xretain和release倒底怎么玩
cocos2d-xretain和release倒底怎么玩
& 作者及来源: wanqi - 博客园 &
&收藏到→_→:
摘要: cocos2d-x retain和release倒底怎么玩?
"cocos2d-xretain和release倒底怎么玩"::
转载请注明,原文地址:&http://blog.csdn.net/musicvs/article/details/8689345
1.&为什么会有retain?
c++和java不一样,java有一套很方便的垃圾回收机制,当我们不需要使用某个对象时,给它赋予null值即可。而c++new了一个对象之后,不使用的时候通常需要delete掉。
于是,cocos2d-x就发明了一套机制(小若:发你妹纸。。。),其实红孩儿的博客很详细地解释了cocos2d-x的机制,我没有能力也不想重复解释。(小若:那你还写?=&=)
retain的意思是保持引用,也就是说,如果想保持某个对象的引用,避免它被cocos2d-x释放,那就要调用对象的retain函数。(小若:为什么不retain就会被释放?)
2.&真正的凶手autorelease
既然旁白诚心诚意地问我,那我就光明正大地回答吧(小若:我今天没力气吐槽,好吧=&=)。
一旦调用对象的autorelease函数,那么这个对象就被cocos2d-x的机制给盯上了,如果这个对象没人认领,那就等着被释放吧。(小若:=&=太久没吐槽,一时不知道吐什么好)。
3.&看代码实际点
说了这么多,还是上代码吧。
创建一个cocox2d-x的项目,就直接拿helloworldscene开刀,修改init函数,在最后添加一句代码:
[cpp]&view plaincopyprint?
bool&helloworld::init()&&
&&&&bool&bret&=&false;&&
&&&&&&&&&&
&&&&&&&&testsprite&=&ccsprite::create("helloworld.png");&&
&&&&&&&&bret&=&true;&&
&&&&}&while&(0);&&
&&&&return&&&
(小若:testsprite是什么东东?)
testsprite是一个成员变量,在头文件里加上就可以了:
[cpp]&view plaincopyprint?
class&helloworld&:&public&cocos2d::cclayer&&
&&&&virtual&bool&init();&&&&
&&&&static&cocos2d::ccscene*&scene();&&
&&&&void&menuclosecallback(ccobject*&psender);&&
&&&&create_func(helloworld);&&
private:&&
&&&&cocos2d::ccsprite*&&&
然后,最关键的来了,我们修改menuclosecallback函数:
[cpp]&view plaincopyprint?
void&helloworld::menuclosecallback(ccobject*&psender)&&
&&&&testsprite-&getposition();&&
现在,运行项目,点击按钮,看看是什么情况?
(小若:报错了!)
如果大家知道怎么调试项目的话,此文来自: 马开东博客
转载请注明出处 网址:
我们在menuclosecallback函数里断点,用调试模式运行项目,看看testsprite对象:
(小若:很正常啊,有什么特别的?)
正你妹纸啊,正!你才正!(小若:不要这么光明正大地赞我o&o!)
我们应该能看到不少非正常数据,图中已经用红色圈圈标出来了,这代表testsprite对象被释放了,现在testsprite指向未知的位置。
这是很危险的,有时候它不会立即报错,但是在某个时刻突然崩溃!
要想解决这个问题,很简单,再次修改init函数:
[cpp]&view plaincopyprint?
bool&helloworld::init()&&
&&&&bool&bret&=&false;&&
&&&&&&&&&&
&&&&&&&&testsprite&=&ccsprite::create("helloworld.png");&&
  testsprite-&retain();&&
&&&&&&&&bret&=&true;&&
&&&&}&while&(0);&&
&&&&return&&&
再次运行项目,看看还会不会报错?(小若:不会了,为什么?)
再次用调试模式运行项目,看看testsprite对象:
(小若:不正常!都是0!!)
零你妹纸=&=(小若:为什么今天你总是抢我的对白o&o!)
这次我们看到testsprite的数据明显正常了。
4.&原理来了
好了,唠叨了一大堆,还没有进入正题。
首先,要想让对象参与机制,必须继承ccobject类(ccnode、cclayer等都继承了ccobject类)。
然后,调用对象的autorelease函数,对象就会被cocos2d-x的机制盯上,在游戏的每一帧,内此文来自: 马开东博客
转载请注明出处 网址:
存管理机制都会扫描一遍被盯上的对象,一旦发现对象无人认领,就会将对象杀死!(小若:嗷~残忍!)
如果不想让对象被杀死,那么就要调用对象的retain函数,这样对象就被认领了,一旦对象被认领,就永远不会被机制杀掉,是永远,一辈子。(小若:好朋友,一辈子=&=)
但,对象一辈子都不被释放的话,那么就会产生内存泄露,你试试加载一个占20m内存的对象一辈子不释放,不折腾死才怪~(小若:你去加载一个20m的对象本身就是闲的那个什么疼啊!)因此,当你不需要再使用这个对象时,就要调用对象的release函数,这是和retain对应的。一般可以在析构函数里调用release函数。
5.&实际情况
讲道理,大家都懂,但是,相信很多朋友在实际写代码的时候,还是会感觉很混乱。
比如,什么时候该retain?大家是不是发现,有时候不retain也不会报错?
其实这很简单,因为我们经常会在create一个对象之后,添加到层里,如:
testsprite&=&ccsprite::create("helloworld.png");
this-&addchild(testsprite);
addchild函数就是导致大家混乱的凶手了,addchild函数会调用对象的retain函数,为什么它要调用对象的retain函数呢?因为你都把对象送给它当孩子了,它当然要认领这个对象了!(小若:我懂了,嗷!)
于是,当我们把对象addchild到cclayer时(不一定是cclayer,ccarray、ccnode都行),我们就不需要调用对象的retain函数了。
6.&那倒底什么时候要retain?
说了这么多,还是没有说清楚,什么时候要调用对象的retain。
很简单,当你把一个对象作为成员变量时,并且没有把对象addchild到另外一个对象时,就需要调用retain函数。
7.&最后的最后
一定要记住,必须要调用了对象的autorelease函数之后,retain和release函数才会生效,否则,一切都是徒劳。
因此,十分建议使用create的方式创建对象,如:
[cpp]&view plaincopyprint?
ccsprite*&ccsprite::create(const&char&*pszfilename)&&
&&&&ccsprite&*pobsprite&=&new&ccsprite();&&
&&&&if&(pobsprite&&&&pobsprite-&initwithfile(pszfilename))&&
&&&&&&&&pobsprite-&autorelease();&&
&&&&&&&&return&&&
&&&&cc_safe_delete(pobsprite);&&
&&&&re搜索此文相关文章:此文来自: 马开东博客
网址: 站长QQ
cocos2d-xretain和release倒底怎么玩_博客园相关文章
博客园_总排行榜
博客园_最新
博客园_月排行榜
博客园_周排行榜
博客园_日排行榜http://blog.csdn.net/musicvs/article/details/8689345
retain和倒底怎么玩?
呼呼,好久没有发布教程了(小若:难得清静了,你为毛又出来吓人=&=),其实最近木头我在准备出版书籍的事情。但是貌似不太顺利,果然我还是积累不够,写书的过程压力好大,感觉写不出有趣的文字出来(小若:嗷、、、)。果然还是在博客写自由一些?嘿嘿~
最近以及最不是很近(小若:书里一定不能出现这些错误的语句,所以你才写不出来吧),不少朋友对的认识似乎有点模糊,今天我就和大家分享一下关于的知识吧
笨木头花心贡献,啥?花心?不呢,是用心~
转载请注明,原文地址:&
1.&为什么会有?
C++和不一样,有一套很方便的垃圾回收机制,当我们不需要使用某个对象时,给它赋予值即可。而了一个对象之后,不使用的时候通常需要掉。
于是,就发明了一套内存管理机制(小若:发你妹纸。。。),其实红孩儿的博客很详细地解释了的内存管理机制,我没有能力也不想重复解释。(小若:那你还写?)
Retain的意思是保持引用,也就是说,如果想保持某个对象的引用,避免它被释放,那就要调用对象的函数。(小若:为什么不就会被释放?)
2.&真正的凶手
既然旁白诚心诚意地问我,那我就光明正大地回答吧(小若:我今天没力气吐槽,好吧)。
一旦调用对象的函数,那么这个对象就被的内存管理机制给盯上了,如果这个对象没人认领,那就等着被释放吧。(小若:太久没吐槽,一时不知道吐什么好)。
3.&看代码实际点
说了这么多,还是上代码吧。
创建一个的项目,就直接拿开刀,修改函数,在最后添加一句代码:
(小若:是什么东东?)
testSprite是一个成员变量,在头文件里加上就可以了:
然后,最关键的来了,我们修改函数:
现在,运行项目,点击按钮,看看是什么情况?
(小若:报错了!)
如果大家知道怎么调试项目的话,我们在函数里断点,用调试模式运行项目,看看对象:
(小若:很正常啊,有什么特别的?)
正你妹纸啊,正!你才正!(小若:不要这么光明正大地赞我!)
我们应该能看到不少非正常数据,图中已经用红色圈圈标出来了,这代表对象被释放了,现在指向未知的位置。
这是很危险的,有时候它不会立即报错,但是在某个时刻突然崩溃!
要想解决这个问题,很简单,再次修改函数:
再次运行项目,看看还会不会报错?(小若:不会了,为什么?)
再次用调试模式运行项目,看看对象:
(小若:不正常!都是!!)
零你妹纸(小若:为什么今天你总是抢我的对白!)
这次我们看到的数据明显正常了。
4.&原理来了
好了,唠叨了一大堆,还没有进入正题。
首先,要想让对象参与内存管理机制,必须继承类(、等都继承了类)。
然后,调用对象的函数,对象就会被的内存管理机制盯上,在游戏的每一帧,内存管理机制都会扫描一遍被盯上的对象,一旦发现对象无人认领,就会将对象杀死!(小若:嗷残忍!)
如果不想让对象被杀死,那么就要调用对象的函数,这样对象就被认领了,一旦对象被认领,就永远不会被内存管理机制杀掉,是永远,一辈子。(小若:好朋友,一辈子)
但,对象一辈子都不被释放的话,那么就会产生内存泄露,你试试加载一个占内存的对象一辈子不释放,不折腾死才怪(小若:你去加载一个的对象本身就是闲的那个什么疼啊!)因此,当你不需要再使用这个对象时,就要调用对象的函数,这是和对应的。一般可以在析构函数里调用函数。
5.&实际情况
讲道理,大家都懂,但是,相信很多朋友在实际写代码的时候,还是会感觉很混乱。
比如,什么时候该?大家是不是发现,有时候不也不会报错?
其实这很简单,因为我们经常会在一个对象之后,添加到层里,如:
testSprite&=&CCSprite::create(&HelloWorld.png&);
this-&addChild(testSprite);
addChild函数就是导致大家混乱的凶手了,函数会调用对象的函数,为什么它要调用对象的函数呢?因为你都把对象送给它当孩子了,它当然要认领这个对象了!(小若:我懂了,嗷!)
于是,当我们把对象到时(不一定是,、都行),我们就不需要调用对象的函数了。
6.&那倒底什么时候要?
说了这么多,还是没有说清楚,什么时候要调用对象的。
很简单,当你把一个对象作为成员变量时,并且没有把对象到另外一个对象时,就需要调用函数。
7.&最后的最后
一定要记住,必须要调用了对象的函数之后,和函数才会生效,否则,一切都是徒劳。
因此,十分建议使用的方式创建对象,如:
这些就是retain表面上的知识了,至于retain源码级别的解说,请到红孩儿的博客吧,强烈推荐~
好了,不唠叨了困喇,睡大觉去
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:171194次
积分:4522
积分:4522
排名:第6225名
原创:229篇
转载:375篇
评论:92条
阅读:1781
阅读:2882
阅读:1274
文章:38篇
阅读:11529
(1)(2)(10)(1)(1)(4)(1)(4)(25)(80)(71)(18)(9)(20)(107)(7)(9)(28)(11)(12)(8)(13)(58)(34)(40)(10)(22)下次自動登錄
現在的位置:
& 綜合 & 正文
【木頭Cocos2d-x 037】retain和release倒底怎麼玩?
retain和倒底怎麼玩?
呼呼,好久沒有發布教程了(小若:難得清靜了,你為毛又出來嚇人= =),其實最近木頭我在準備出版書籍的事情。但是貌似不太順利,果然我還是積累不夠,寫書的過程壓力好大,感覺寫不出有趣的文字出來(小若:嗷、、、)。果然還是在博客寫自由一些?嘿嘿~
最近以及最不是很近(小若:書里一定不能出現這些錯誤的語句,所以你才寫不出來吧),不少朋友對的認識似乎有點模糊,今天我就和大家分享一下關於的知識吧
笨木頭花心貢獻,啥?花心?不呢,是用心~轉載請註明,原文地址:
1. 為什麼會有?
C++和不一樣,有一套很方便的垃圾回收機制,當我們不需要使用某個對象時,給它賦予值即可。而了一個對象之後,不使用的時候通常需要掉。
於是,就發明了一套內存管理機制(小若:發你妹紙。。。),其實紅孩兒的博客很詳細地解釋了的內存管理機制,我沒有能力也不想重複解釋。(小若:那你還寫?)
Retain的意思是保持引用,也就是說,如果想保持某個對象的引用,避免它被釋放,那就要調用對象的函數。(小若:為什麼不就會被釋放?)
2. 真正的兇手
既然旁白誠心誠意地問我,那我就光明正大地回答吧(小若:我今天沒力氣吐槽,好吧)。
一旦調用對象的函數,那麼這個對象就被的內存管理機制給盯上了,如果這個對象沒人認領,那就等着被釋放吧。(小若:太久沒吐槽,一時不知道吐什麼好)。
3. 看實際點
說了這麼多,還是上代碼吧。
創建一個的項目,就直接拿開刀,修改函數,在最後添加一句代碼:
bool HelloWorld::init()
bool bRet =
/* 很多代碼被省略了。。。。。。 */
testSprite = CCSprite::create("HelloWorld.png");
} while (0);
(小若:是什麼東東?)
testSprite是一個成員變量,在頭文件里加上就可以了:
class HelloWorld : public cocos2d::CCLayer
virtual bool init();
static cocos2d::CCScene* scene();
void menuCloseCallback(CCObject* pSender);
CREATE_FUNC(HelloWorld);
cocos2d::CCSprite* testS
然後,最關鍵的來了,我們修改函數:
void HelloWorld::menuCloseCallback(CCObject* pSender)
testSprite-&getPosition();
現在,運行項目,點擊按鈕,看看是什麼情況?
(小若:報錯了!)
如果大家知道怎麼調試項目的話,我們在函數里斷點,用調試模式運行項目,看看對象:
(小若:很正常啊,有什麼特別的?)
正你妹紙啊,正!你才正!(小若:不要這麼光明正大地贊我!)
我們應該能看到不少非正常數據,圖中已經用紅色圈圈標出來了,這代表對象被釋放了,現在指向未知的位置。
這是很危險的,有時候它不會立即報錯,但是在某個時刻突然崩潰!
要想解決這個問題,很簡單,再次修改函數:
bool HelloWorld::init()
bool bRet =
/* 很多代碼被省略了。。。。。。 */
testSprite = CCSprite::create("HelloWorld.png");
  testSprite-&retain();
} while (0);
再次運行項目,看看還會不會報錯?(小若:不會了,為什麼?)
再次用調試模式運行項目,看看對象:
(小若:不正常!都是!!)
零你妹紙(小若:為什麼今天你總是搶我的對白!)
這次我們看到的數據明顯正常了。
4. 原理來了
好了,嘮叨了一大堆,還沒有進入正題。
首先,要想讓對象參與內存管理機制,必須繼承類(、等都繼承了類)。
然後,調用對象的函數,對象就會被的內存管理機制盯上,在遊戲的每一幀,內存管理機制都會掃描一遍被盯上的對象,一旦發現對象無人認領,就會將對象殺死!(小若:嗷殘忍!)
如果不想讓對象被殺死,那麼就要調用對象的函數,這樣對象就被認領了,一旦對象被認領,就永遠不會被內存管理機制殺掉,是永遠,一輩子。(小若:好朋友,一輩子)
但,對象一輩子都不被釋放的話,那麼就會產生內存泄露,你試試加載一個占內存的對象一輩子不釋放,不折騰死才怪(小若:你去加載一個的對象本身就是閑的那個什麼疼啊!)因此,當你不需要再使用這個對象時,就要調用對象的函數,這是和對應的。一般可以在析構函數里調用函數。
5. 實際情況
講道理,大家都懂,但是,相信很多朋友在實際寫代碼的時候,還是會感覺很混亂。
比如,什麼時候該?大家是不是發現,有時候不也不會報錯?
其實這很簡單,因為我們經常會在一個對象之後,添加到層里,如:
testSprite = CCSprite::create("HelloWorld.png");
this-&addChild(testSprite);
addChild函數就是導致大家混亂的兇手了,函數會調用對象的函數,為什麼它要調用對象的函數呢?因為你都把對象送給它當孩子了,它當然要認領這個對象了!(小若:我懂了,嗷!)
於是,當我們把對象到時(不一定是,、都行),我們就不需要調用對象的函數了。
6. 那倒底什麼時候要?
說了這麼多,還是沒有說清楚,什麼時候要調用對象的。
很簡單,當你把一個對象作為成員變量時,並且沒有把對象到另外一個對象時,就需要調用函數。
7. 最後的最後
一定要記住,必須要調用了對象的函數之後,和函數才會生效,否則,一切都是徒勞。
因此,十分建議使用的方式創建對象,如:
CCSprite* CCSprite::create(const char *pszFileName)
CCSprite *pobSprite = new CCSprite();
if (pobSprite && pobSprite-&initWithFile(pszFileName))
pobSprite-&autorelease();
return pobS
CC_SAFE_DELETE(pobSprite);
return NULL;
這些就是retain表面上的知識了,至於retain源碼級別的解說,請到紅孩兒的博客吧,強烈推薦~
好了,不嘮叨了困喇,睡大覺去
&&&&推薦文章:
【上篇】【下篇】

我要回帖

更多关于 mqtt retain 的文章

 

随机推荐