现在我们需要讨论一下内存管理和自动释放内存消息.
通常, 在objective-C中创建对象的时候,你会调用alloc方法. 这么做之后, 你就有责任在你不再需要它的时候释放它所占用的内存. 下面是典型的alloc/init 和release周期.
// allocate a new instance of NSObject
NSObject* myObject = [[NSObject alloc] init];
// do something with myObject here …
// release the memory used by myObject
// if you don’t release it, the object is leaked and the memory used by it is never freed.
[myObject release];
现在,有了autorelease消息和iOS应用总是使用的自动释放池, 就不再需要发送release消息了.
下面是用autorelease重写的相同的例子.
// allocate a new instance of NSObject
NSObject* myObject = [[[NSObject alloc] init] autorelease];
// do something with myObject here ...
// no need to call release, in fact you should not send release as it would crash.
可以看到, 这样简化了内存管理工作, 你不再需要惦记着发送release消息了.自动释放池会在随后帮你向对象发送release消息. 因为需要添加autorelease消息,创建对象的过程变得稍微复杂了一点.
考虑下面的代码, 它说明了按照传统的内存释放周期如何为CCNode对象分配内存.
// allocate a new instance of CCNode
CCNode* myNode = [[CCNode alloc] init]];
// do something with myNode ...
[myNode release];
不建议用这种方式创建cocos2d对象.使用静态的初始化器方法来返回自动释放内存对象,更加方便.和苹果推荐的方式不同,通过把[[[NSObject alloc] init] autorelease]调用移动到类自身的静态方法中, autorelease的使用被内置在了cocos2d的设计中. 这是很好的做法,不要抵触它.这会让你更加轻松, 因为你不再需要记住那个对象需要释放.手工释放内存, 常常会要么由于过度释放而导致程序崩溃, 要么由于忘记释放内存而导致内存泄漏.
在CCNode类中,静态初始化器是+(id) node, 下面的代码发送一个alloc消息给self, 等同于在CCNode类的实现中的[CCNode alloc].
+(id) node
{
return [[[self alloc] init] autorelease];
}
这种情况下通常使用self, 这是合法的. 这对于C++程序员来说可能不太容易理解.
看下面的代码,我们使用静态初始化器重写CCNode对象的分配.很明显, 代码变得短小,简明和整洁了. 这就是我喜欢的方式.
// allocate a new instance of CCNode
CCNode* myNode = [CCNode node];
// do something with myNode .
这就是使用自动释放内存的对象的优雅之处.你不必惦记着给它们发送release消息.每次cocos2d进入到下一帧, 不再被使用的自动释放内存对象会被自动释放掉.但是有一点需要注意,如果使用这段代码,只要后面有一个帧企图访问myNode对象, 这时候他已经被释放了,发送任何消息给它将会导致一个EXC_BAD_ACCESS异常.
仅仅把CCNode* myNode变量添加到类的成员变量中,并不意味着这个对象所使用的内存会被自动地保留. 如果你希望在后面的帧中保留自动释放内存对象,你必须保留对这个对象的引用,然后相应地释放它, 除非显式地加入到类的子节点中.
下面介绍一种比较好的方式,不需要显示调用retain方法也可以保持自动释放内存对象.通常创建了CCNode对象后,作为子节点添加到另一个CCNode子类的对象,这样就可以把这些CCNode对象加入到场景层次中.如果你愿意甚至可以删除这些成员变量,依赖cocos2d来为你存储对象.
// creating an autorelease instance of CCNode
-(void) init
{
myNode = [CCNode node];
myNode.tag = 123;
// adding the node as children to self (assuming self is derived from CCNode)
[self addChild:myNode];
}
-(void) update:(ccTime)delta
{
// later access and use the myNode object again
CCNode* myNode = [self getChildByTag:123];
// do something with myNode
}
内幕在于, addChild把对象添加到容器中, 例子中使用的是CCArray, 和iPhone SDK提供的NSMutableArray相似, 但是更快. CCArray,NSMutableArray和其它iPhone SDK的容器自动发送一个retain消息给加入其中的所有对象, 当它们从容器中移除时再给它们发送一条release消息.这样对象可以一直保持有效以便随后的访问, 同时,当它们从容器中移除时也可以被自动释放掉.
需要牢记的是,我在这里讨论的关于cocos2d的管理内存的方法是最好的. 你可能会遇到其他开发人员说自动释放内存不好或者缓慢而不应该使用.别听他们的.
提示:苹果开发者文档建议减少使用自动释放内存的对象的数量.然而,大多数cocos2d对象,都是作为自动释放内存对象创建的.这让内存管理更加容易,就像上面展示的那样.
如果你在每一个cocos2d对象上使用alloc/init和release方法, 你会陷入到很多毫无益处的痛苦中.也并不是说永远不要使用alloc/init, 它有它的作用,有时候甚至是必需的.但是对于cocos2d对象, 你应该使用静态自动释放内存初始化器.
自动释放内存对象只有一点需要注意.它们的内存会一直被占用, 直到游戏进入到下一帧.这就意味着如果你在每一帧中创建了大量舍弃式自动释放内存的对象, 会非常浪费内存.但是这实际上很少发生.
以上是我对cocos2d内存管理的快速入门.在Objective-C的世界,内存管理遵循两条简单的规则:
■ 如果你拥有(alloc, copy或者retain)一个对象, 你必须在随后释放它.
■ 如果你发送了autorelease消息给一个对象, 你不必释放它.
更深入的关于内存管理的讨论,请参阅苹果的内存管理编程指南(Apple’’s Memory Management Programming Guide):
(http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Memor yMgmt/MemoryMgmt.html).
进化
像helloWorld这样的模板项目,如果不进行一些加工又有什么作用呢? 下面我会教你对触摸事件作出响应. 如何开始呢?
首先,在init方法中作两处改变,允许触摸输入和使用tag值以便随后通过此值取得label对象.修改的代码在列表2-3中以高亮显示.
列表 2–3. 允许触摸输入和使用tag值
-(id) init
{
if ((self = [super init])) {
// create and initialize a label
CCLabel* label = [CCLabel labelWithString:@"Hello World"
fontName:@"Marker Felt" fontSize:64];
// get the window (screen) size from CCDirector
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label at the center of the screen
label.position = CGPointMake(size.width / 2, size.height / 2);
// add the label as a child to this Layer
[self addChild: label];
// our label needs a tag so we can find it later on
// you can pick any arbitrary number
label.tag = 13;
// must be enabled if you want to receive touch events!
self.isTouchEnabled = YES;
}
return self;
}
label对象的tag属性值被赋予13. 为什么这么做呢? 让你这么做一定是有原因的,对吧? 在前面一节中,我解释过怎样访问类的子节点对象—通过tag属性值找到它.tag属性的值可以是任意的正整数,而且每一个对象必须有它自己的唯一的tag数值, 否则你就不能标识你想要的的对象.
贴士:不要使用像13这样的魔法数字作为tag的值,应该养成定义常量来表示这些tag的值.相对于使用像kTagForLabel这样的定义良好的常量,以后你将很难想起tag值13代表的是怎样的对象. 我将会在第5章讨论这个问题.
其次,self.isTouchEnabled被设置成YES, 这是CCLayer的属性,并且告诉它你想要接收触摸消息.这时候ccTouchesBegan方法会被调用:
-(void) ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
{
CCLabel* label = (CCLabel*)[self getChildByTag:13];
label.scale = CCRANDOM_0_1();
}
使用[self getChildByTag:13], 可以得到CCLabel对象, 它的tag值在init方法中被设定.你可以和平常一样使用这个label. 在上面的代码中,我们使用cocos2d中非常方便的宏CCRANDOM_0_1() 让这个文本标签的大小在0和1之间变化. 每次你触摸屏幕,标签的大小都会改变.
因为getChildByTag方法总是返回label对象, 所以我们可以安全地把它转换成(CCLabel*)对象.但是需要注意的是,如果某种原因导致得到的对象不是从CCLabel类继承的对象,你的应用将崩溃.这很容易发生在你不小心将另一个对象的tag值也同样设置成了13. 因为这个原因,采用防御性的编程风格,确认一下你所得到的数据确实是你预期的数据,是一个很好的做法.防御性编程使用断言来确认假设是正确的.现在,你可以使用NSAssert方法:
-(void) ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
{
CCNode* node = [self getChildByTag:13];
// defensive programming: verify the returned node is a CCLabel class object
NSAssert([node isKindOfClass: [CCLabel class]], @"node is not a CCLabel!");
CCLabel* label = (CCLabel*)node;
label.scale = CCRANDOM_0_1();
}
本例中,我们期待的 getChildByTag 方法返回的节点对象是CCLabel类型的对象.但是我们并不确定,于是我们加了NSAssert来确认这个事实.这对于在程序崩溃前发现错误是很有帮助的.
这里增加了2行代码, 但是从性能的角度来看是一样的.NSAssert的调用在发布(Release)版的构建中会被完全消除.类型转换操作CCLabel* label = (CCLabel*)node; 也是做过的,只是在同一行中.总之, 两个版本的执行结果完全相同, 但是在第二个版本中,如果你没有得到期望的CCLabel对象,你会得到有用的提示信息, 而不是EXC_BAD_ACCESS崩溃信息.
还需要了解什么
因为这是入门的章节,我认为有必要向你介绍一些关于iOS的重要的但是经常被忽视的方面.我希望你了解各种iOS设备之间一些微妙的差异.特别是可用内存的大小常常被误解.因为你只能安全地使用每个设备的内存的一部分.
我也希望让你知道iPhone模拟器是测试你的游戏的一个非常好的工具, 但是它无法用来测量性能,内存的使用,以及其它一些特性.模拟器的体验和运行在实际的iOS设备上是有很大的不同的.不要落入基于iPhone 模拟器上游戏运行的效果来对游戏进行评价的陷阱.这只能依赖于实际的设备.
iOS设备
当你为各种iOS设备开发应用时,你需要考虑到他们之间的差异.大多数独立的游戏开发爱好者不会购买每个有着细微差异的iOS设备.但是至少我们需要理解他们之间的一些重要的差异.
你可以参阅苹果的规格表来熟悉iOS设备的技术规格.下面的链接分别列出了iPhone, iPod Touch和iPad的规格参数.
http://support.apple.com/specs/#iphone
http://support.apple.com/specs/#ipodtouch
http://support.apple.com/specs/#ipad
表2-1总结了和游戏开发相关的重要的硬件差异.表中列出的iPod Touch设备用”代” 作区分,是因为苹果不使用”3G”的后缀来命名iPod Touch的系列产品.这张表向你展示了iOS 设备之间不像你想象的那么同质.注意iPhone 4的显卡芯片是未知的,因为它首次集成在CPU中.
表2-1 iOS硬件差异
Device Processor Graphics Resolution Memory (RAM)
First generation devices 412 MHz PowerVR MBX 480x320 128 MB
iPhone 3G (second generation.) 412 MHz PowerVR MBX 480x320 128 MB
iPod Touch (second generation) 532 MHz PowerVR MBX 480x320 128 MB
Third generation devices 600 MHz PowerVR SGX535 480x320 256 MB
iPad 1000 MHz PowerVR SGX535 1024x768 256 MB
IPhone 4 1000 Mhz Unknown 960x640 512 MB
可以看到,每个更新一代的iOS设备通常都会有更快的CPU,更强的图形芯片,更大的内存和更高的分辨率.这个趋势还将继续,新的设备会变得越来越强大.如果你打算通过iOS游戏赚钱的话,记住旧型号的设备仍然有相当大的市场份额,这种市场份额的变化非常的慢,比新型号设备发布的速度要慢很多.甚至在今天,如果不让你的游戏支持第二代的设备,那么就等于放弃了相当大的一块市场.
通常,当游戏开发者研究硬件特性的时候,他们倾向于关注CPU的速度和图形芯片来评估可以采用的技术.然而,作为一种移动设备的iOS设备,直到最近的iPhone4, 仍然更多地受限于可用内存的大小.
提示:不要把内存(RAM)和闪存(flash storage memory)搞混淆了.闪存用来存储MP3,视频,应用程序和图像等文件,iOS设备最小的也有8G的闪存. 闪存相当于桌面电脑的硬盘.内存是应用程序在运行时用来存储代码,数据和材质的的地方.
转载请注明出处:http://blog.sina.com.cn/mountlook
分享到:
相关推荐
在Cocos2D-X2.2.3的学习过程中,内存管理是至关重要的一个环节,它直接影响到游戏的性能和稳定性。Cocos2D-X是一个跨平台的2D游戏开发框架,使用C++作为主要编程语言,并支持Lua和JavaScript。本笔记将深入探讨Cocos...
cocos2d-x不仅适用于游戏开发,还可以用于创建教育软件、互动媒体和其他2D图形应用,其强大的场景管理、精灵(Sprite)系统和粒子效果等功能,使得开发者能够快速构建各种复杂的2D场景。 总的来说,cocos2d-x 2.2.2...
8. **性能优化**:提供关于代码优化、内存管理和渲染优化的建议,以提高游戏性能。 9. **发布与跨平台**:指导如何将游戏打包并发布到不同的平台,如iOS、Android和Web。 10. **Cocos2d-JS特定特性**:可能包含...
11. **性能优化**:3.8版本在内存管理和渲染效率上进行了优化,确保游戏运行流畅。 12. **扩展性**:cocos2d-x提供了插件系统和扩展API,方便开发者添加自定义功能和第三方库。 在学习和使用cocos2d-x 3.8时,...
C++的使用可以提供更好的性能和更直接的内存管理,同时也能充分利用面向对象编程的特性来构建复杂的游戏逻辑。 源代码部分通常包含以下关键知识点: 1. **场景(Scene)与层(Layer)管理**:Cocos2d-x使用场景和...
本书可能会详细讲解Cocos2d-x中的内存管理机制,如自动引用计数(ARC)和弱引用,以及如何通过优化代码和数据结构来提高游戏运行效率。 最后,还会涉及到Cocos2d-x的构建系统和发布流程,包括多平台支持、资源打包...
《Cocos2d-x实战 JS卷》是一本深入探讨Cocos2d-x游戏开发的专著,主要聚焦于使用JavaScript语言进行游戏编程。Cocos2d-x是一个开源的游戏开发框架,广泛应用于移动设备和桌面平台,支持iOS、Android、Windows等多...
在资源管理方面,Cocos2d-x 3.13.1版本优化了资源加载和释放机制,这有利于减少内存消耗,提高游戏性能。开发者需要确保正确地加载和释放Spine动画资源,避免内存泄漏。此外,考虑到移动设备的性能限制,合理地优化...
最后,本书可能会探讨性能优化技巧,如内存管理、渲染优化、代码调试等,帮助开发者提升游戏运行效率,确保游戏在各种设备上都能流畅运行。 总的来说,《Cocos2d-x 3.x游戏开发实战》是一本全面覆盖Cocos2d-x 3.x...
10. **性能优化**:Cocos2d-x 3.1对内存管理和渲染效率进行了优化,以确保在不同设备上的流畅运行。 11. **脚本支持**:虽然3.1版本主要以C++为主,但Cocos2d-x也支持Lua和JavaScript,允许开发者选择更适合自己的...
1. 性能优化:2.1.4版本对内存管理、渲染效率等方面进行了优化,降低了游戏运行时的资源消耗,提高了游戏的运行速度。 2. 稳定性提升:修复了大量的bug,确保了框架在各种环境下的稳定运行,减少了游戏崩溃的可能性...
11. **Performance Improvements**:Cocos2d-iPhone 2.0在性能上做了大量优化,包括更快的渲染、内存管理和多线程支持。 12. **Multitouch Support**:针对iOS设备的多点触控特性,Cocos2d-iPhone提供了易于使用的...
7. **场景管理(Scene Management)**:场景是游戏的逻辑单位,Cocos2d-js提供了一种场景切换机制,允许在不同场景间平滑过渡。 8. **图集和精灵表(Atlases & Sprite Sheets)**:为了优化性能,Cocos2d-js支持...
cocos2d 提供了纹理图集(Texture Atlas)和plist文件来优化资源加载,减少内存占用。 七、发布与调试 完成游戏开发后,你需要打包应用并进行测试。cocos2d 支持在模拟器和真机上进行调试,通过Xcode的调试工具可以...
1. 性能提升:cocos2d-x 3.13.1版本在性能方面做了大量优化,包括内存管理、渲染效率等方面的改进,使得游戏运行更加流畅。 2. 脚本支持:该版本增强了Lua和JavaScript的绑定,让开发者可以选择更适合自己的脚本语言...
总结,通过深入研究"runningGame"的源码,我们可以了解到cocos2d-x在跑酷游戏开发中的应用,掌握从资源管理到游戏逻辑实现的全过程。这对于开发者来说,既是一次实践操作的锻炼,也是一次理论知识的巩固,对于后续的...
3.x版本是其一个重要的更新,引入了许多新特性,包括更高效的内存管理、支持C++11等。 3. **网络请求**:在cocos2d-x中,可以使用`cocos2d::network::HttpClient`类进行网络请求。你需要创建一个请求,设置URL...
Cocos2d-x有内置的资源管理模块,如Texture2D、SpriteFrameCache等,用于加载和缓存图像资源,AudioEngine用于播放音频。 6. **Lua脚本集成**:Cocos2d-x支持Lua作为脚本语言,可以用来编写游戏逻辑,与C++代码混合...
Cocos2d-x还提供了一些基础功能模块,如内存管理模型、纹理资源的加载和缓存,以及一组数据容器,使得STL中的容器能够与Cocos2d-x的内存管理模型相结合。 渲染系统作为Cocos2d-x的核心部分,它不仅负责场景元素的...
9. **性能优化**:Cocos2d-JS 进行了多方面的性能优化,包括内存管理、渲染性能等,确保在不同设备上都能流畅运行。 在这个“js-tests”目录下,可能包含了各种 Cocos2d-JS 的功能测试案例,比如精灵动画、粒子效果...