基于Cocos2D的IOS游戏开发进阶与实践 —— Stage 2 —— 学习笔记

Object C


哪怕开发Cocos 2D使用的是C++,也需要Object C,

Object C是IOS的第一语言,比如用到保存数据,或者调用其他接口时都需要Object C



Object C与C/C++语言类似,也有头文件和可执行文件的概念

只不过它的可执行文件是以.m文件命名的,.m文件中是代码的实现

还有.mm文件,是为了与C++语言混合编程时使用的




import关键字与C/C++中的include关键字相同,是为了包含头文件的


头文件中一般存放类和函数的声明部分,可执行文件是代码实现的部分



Object C是C语言的扩展,所以是向下兼容的,所以可以在Object C中写C的代码



与C语言不同,Object C的布尔变量的声明为大写的BOOL,而且值为YES和NO



C语言中的null在Object C语言中变为了nil,常用来表示指针的初始值



Object C中所有的对象都需要使用指针,除了C风格的结构体之类的基本数据


如果不带指针的去声明一个对象就会报错



如果无法确定一个指针指向的对象的类型时,使用id表示,等于C++中的void







@""表示的是声明了一个临时的NSString的变量,这实际上是一种简写的方式

@"OK"表示定义了一个临时的变量,完整的表示应当是




函数调用


官方的说法不是函数调用,而是用中括号的这种形式向这个对象发送了一个消息



在头文件中使用@interface和@end之间声明一个类



:NSObject表示该类继承的类,NSObject是大多数类的父类



大括号之间定义的是成员变量

默认的成员变量都是protected

我们可以通过public将一些成员变量对外访问,但实际上更多的是使用property来实现此种功能




这是定义的发送给对象的消息的定义

前面有加号也有减号,+表示提供给类使用,-表示提供给对象使用,

与C++一样的,+中不能使用对象的成员变量,不能使用this(Object C使用self)指针等


方法后面是参数,参数的类型放在冒号分割后的括号中,后面带参数

多个变量的参数不仅要指定类型和参数的名称,还要有一个用户自定义的描述性的语句(例如"Folder:")



在对应的实现文件中

实现一个类使用@implementation和@end






在C和C++中都有函数指针的概念

在Object C用到函数指针使用@selector

例如定义了这样一个函数



调用时:




也可以直接调用一个函数






Object C内存管理

引用计数的方式管理内存


C和C++中,使用malloc或者new申请一块内存,

相对应的,当不需要再使用这部分对象时,使用free或者delete把内存还给系统

不好的地方是,如果创建了内存没有释放,将会变成一块无法释放的内存,成为内存泄露,程序崩溃

所以这种纯手动的内存管理是饱受诟病的


在Java和C#中采用的是垃圾回收机制,不用再关心内存管理的部分


Object C中采用了引用计数的方式

当申请内存时,引用计数为1,在引用则加1,引用多少处,则增加多少

当引用结束,则将引用计数减1,当引用计数变为0时,系统将收回这部分内存


alloc:申请一块内存(创建对象),引用计数自动为1

retain:引用这个对象,引用计数加1

release:对对象的引用结束,与retain正好相反,配对使用

但如果retain了没有对应的release,或者release一个已经销毁的对象(重复release了),都会出问题






alloc分配内存,引用计数+1

init初始化对象

autorelease标记它的引用计数在下一个时刻减1,但不是立刻(非常快)

autorelease实际上是把对象放在一个pull中,在系统运行的下一帧,将这个pull中的对象都release掉

往往是用在一个作用域内创建的一个对象,在作用域外使用它,这时候使用autorelease


node方法返回的对象,layer获取到了,这时候没有release,只有autorelease

如果要使用这个layer,需要retain一次

有个宏定义确实retain了这个layer


object传入的就是layer,然后被retain,这样引用计数+1,就不会被销毁了



其实这种引用计数的办法十分繁琐,需要保证对象被正确引用和销毁才可以

所以才有了ARC这种方式



ARC(Auto Reference Counting)自动引用计数

如果enable了ARC,则不需要手动的retain和release,ARC将会自动管理计数(性能可能会稍有损耗)




IOS5之前没有ARC,所以之前的代码也需要了解普通的retain和release的原理

你可以在你的工程中引用ARC,并指定哪些部分使用ARC,哪些部分不使用






Object C 独特语法

Property

属性,使一些变量能在对象外部访问、使用

 

内部的一些变量需要外部访问时,最好使用getter和setter方法

很多语言当中都有内置的机制可以简单的创建而不用手动编写,Object C中的机制就是property

 

 

property的声明

 

这里的声明相当于声明了这样的函数:

-(NSString*) name; // Object C中一般不使用getXXX

-(void)setName:(NSString*) name;

 

property的实现

 

这里的实现相当于实现了这样的函数:

-(NSString*) name { return _name; }

-(void) setName:(NSString *)name { _name = name; };

 

调用property定义的变量很简单,只需要像调用方法一样调用即可

其实只是编写的时候没有自己编写get和set方法而已,编译时系统会自动生成,所以能直接调用

 

一定要特别注意get方法的写法,习惯上是没有get的

set方法有两种表达方式,一种是set,一种是“.”,两种方法在效果上是一致的

 

 

property定义时后面括号内属性的意思:

nonatomic:

非原子操作,非原子操作和原子操作主要用在多线程中

如果不指定nonatomic,则默认是原子操作,

原子操作在多线程中不能被打断,系统会为它加上线程同步的机制,防止操作被打断

如果开发的游戏是一个单线程的程序,可以使用nonatomic,在性能上获得一点优势

 

copy:

相当于在实现这个变量的set方法时,将变量copy一份赋给成员变量

 

strong:强引用

相当于在实现这个变量的set方法时,将变量计数+1

(这里代码貌似有误,看懂意思就行)

为什么不直接使用retain而是用strong关键字呢?

是因为有了ARC之后代码中不允许出现retain和release关键字,所以改为了strong

 

assign:

直接取它的引用地址,也不增加其引用计数

 

最简单最干净的关联方式,尤其是基础类型的变量使用assign较好,避免copy的发生

少用copy,多用assign和strong

 

readwrite:

指的是getter和setter函数都会生成,默认不填的时候就是readwrite

 

readonly:

只会生成getter函数,不生成setter函数,防止外部改写变量值

 

getter = getName和setter = setName:

可以自定义getter和setter的方法名称

 

 

 

Categories

扩展一些对象的方法,不通过继承,可以扩展任何对象的方法,甚至是没有源代码

 

 

CCSprite是Cocos 2D中的精灵的类,后面的(AdvActions)的就是Categories

给我们提供了能够向现已有的类中可以添加新的方法的途径

只需要定义Categories,指定Catgories的名字并且添加两个方法即可

这样所有的CCSprite的对象就都多了这两个方法

在C++中想要实现类似的功能只能重载CCSprite在其派生类中实现,在OC中更加灵活

 

自定义方法的实现

 

 

但是也要注意,重写的方法可能会覆盖类本身的方法

重写了方法以后,重写的方法不但会在你的代码中起作用,而且会在其他的代码中也会起作用

如果改变了某些代码的行为,可能导致系统中整个代码都是用替换了的代码

所以没有把握不要重写类原有的方法

 

还有一点,Categories可以添加方法,但是不能添加成员变量

 

Protocol

类似于Java中的interface,也有不同

在C和C++中使用虚基类的方式实现相应的功能

 

@protocol和@end之间指定了一组方法

声明支持此协议的类必须提供指定的方法,如果不提供编译器就会报错(如第一个方法)

@optional的也可以选择性提供或者不提供(如第二个方法)

 

协议的使用方式:

在类定义时使用尖括号声明要遵守的协议,可以使用多个协议,使用逗号隔开


在头文件中不需要再声明协议的函数(不是必须的),只需要在实现中实现协议的函数即可


delegate与protocol是息息相关的,主要是用来在对象之间通信的

普通情况下是直接调用

B上有一个A的对象的指针,在B如果发生了事件,只需要用过A的对象的指针就能通知A

 

而是用了protocol之后B不直接记录A的指针

 

这样的好处是解耦和,delegate可以是A,也可以是其他实现了协议的类的对象,灵活


这里的delegate_可以是实现了协议的任何类的对象

 

可以直接使用delegate调用方法了

 


在声明支持协议的类中可以将self赋值给delegate

建立了这种联系

 

 

实际例子的图表


 

 

又如

 定义了一个OS_Effect的协议,内有三个方法

 

OS_LightningCHain这个类就实现了这个协议

 

对于实现了相同协议的类(也不需要是相同基类),可以通过各种方式调用方法

 

 

 

Block

是一段可以嵌入程序的代码,尤其是处理菜单项的时候,或者苹果api的回调

逻辑上一样的代码,哪怕在时间上不是同一时间发生,也可以放在一起

 

 

相当于一个函数指针

block的定义以“^”开始,后面还可以有参数

 

block很方便但也很容易出现问题

1、永远不要再block中使用self指针,为了避免循环引用

 

如果使用的是self,那么self会被block引用,block会被CCMenuItem引用,

CCMenuItem会被Menu引用,Menu又会加到页面上被self引用形成循环

一旦形成循环引用,所有的对象都等待着被引用者释放,但循环的有都不会释放,所以永远不能destroy(走不到dealloc)

所以为了避免循环引用,所以添加了红色框中的内容

前面有两个下划线的关键字__block,表示copy_self不是进行引用,而是相当一个别名,避免循环引用的问题

 

2、Block中对栈内的变量进行只读copy

 

所以如果在block代码块之后修改值,在block代码中打印,block代码中的值是之前的copy,而与之后的赋值无关

 

如果想要赋值,需要声明__block

 

此时不做只读copy,而是直接引用,此时就会输出之后修改过的值了(之前的例子输出2,而不是1)

 

 

Dynamic Message 动态消息

 selector相当于函数的指针

 

也可以定义一个变量

 

但如果方法的名称不存在,或者打错,程序可能会crash

所以可以加上一些保护条件

 

 

 

 

 

 

 

Foundation Framework是苹果创建的最基本的一个framework

 

 

 

 

NSString


 

 

组合变量生成字符串

 

 

本地化(NSString内置了本地化的解决方案)


可以自动去字符表里查找是否有各语言版本的字符串,与设备上设置的语言相关

 (具体本地化方法在第五阶段详细介绍)

 

可以再Dash中查看NSString类的所有方法

 

 分割字符串

 

 

 

 

 NSArray和NSMutableArray

一组按一定顺序排列的对象的序列

往往从0开始计数

 

NSArray创建后就不能再修改,可以看做数组

NSMutableArray可以任意添加、删除、修改、插入,可以看做链表

使用哪个关键看性能和需求

NSMutableArray其实是添加时创建了一部分新的内存,将原本的数据拷贝进去

但是如果数据经常变化,NSMutableArray则能有更大的便利

 

NSArray

 

里面可以存放任何NSObject的派生类对象,不需要类型相同,只需要使用时判断类型即可

(常犯的错误是把基本类型的数据放入NSArray,比如int,char字符串等)

最后一个nil代表结束,但不能在中间使用nil,不然遇到nil的话就会认为是结束了

 

 

NSMutableArray基本使用也也NSArray类似,添加了一些添加、删除和插入的方法

arrayWithCapacity是一个预先设定的容量,如果添加对象时数目超了会自动扩容

但是自动扩容也是有很大代价的,,而如果设置的capaacity太大会造成内存的浪费,导致app被系统kill掉

所以capacity应当比估算的数目略大即可,应当尽量避免扩容和申请过多内存

 

可以通过NSMutableArray创建一个NSArray

(NSMutableArray继承自NSArray)

 

 

NSArray中数据的读取

 

注意,两种for循环的效果是一样的,第二种中的in如同Java中的“:”

 

 

注意,不要在遍历NSMutableArray时添加或者删除其对象,

否则会因为数组长度的改变,而遍历记录的总数是原来的长度,越界等造成crash

 

如果需要执行相关插入或者删除操作,可以在执行for循环遍历前copy一份

在遍历过程中对copy的数组进行操作,这样就不会造成crash了

 

 

NSNumber

由于NSArray中不支持存放C语言的基本数据类型

所以如果想存放这些数据需要用到NSNumber这个类

NSNumber继承自NSObject,是对基本数据类型的封装

 

获取值时

 

 

 

plist文件

创建一个plist文件

 

 

创建完成后

 

 

默认的plist文件是一个Dictionary类型,可以修改为Array类型

 

 

可以添加项目,每个项目中的对象类型也都可以修改

 

 

可以设置value

 

 

使用文件里的内容

 

 

打印一下file_path

显示的是plist文件的路径

 

CCLOG的输出

断点时可能看不出来,但是可以打印出内容

 

 

使用plist文件可以大大的简化,比添加objects容易许多

但也可能会出现安全性的问题,因为打包后的Bundle的保护性是很薄弱的

比如如果把金币放在这里,就会导致游戏很容易被破解

所以plist中不要存放太重要的东西,敏感信息放在Key Chain中(stage 5讲解)

 

 

 

 

NSDictionary和NSMutableDictionary

它们之间的区别与NSArray和NSMutableArray的区别是相同的

 

通过key - value建立联系,key是唯一的

如果key与已存在的key相同,则会覆盖之前的value

 

 

可以通过plist文件创建Dictionary

 

 

 

 

 

 

 

 

 

NSDictionary与NSArray也可以混合使用

 

 

 

NSMutableDictionary的使用方法基本相同

注意setValue中value的值必须是NSObject的派生类的对象

 

 

这里注意,如果key不存在是插入,如果key存在则就会覆盖value的值

 

 

这里的插入和删除操作都是对NSDictionary和NSMutableArray的操作,

所以数据不会被修改到plist文件中(有时间敲代码确认一下)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值