书接上文。
今天来探讨下oc中数据类型和变量。
相比与java来讲,oc中的数据类型更多元化一些。当然要说变量一定要先明确一些概念,比如程序到底是怎么运行的。
当程序写完并进行编译以后,运行程序,系统就会为程序在内存中开辟一块空间,内存大致是分为4部分,第一部分,是代码段,就是存放程序代码的区域,第二个部分就是数据段,他是用来存放静态变量和字符串常量的,第三部分是堆,堆是用来动态申请内存的,最后一部分就是栈,他是用来存放局部变量的。结合到变量中来理解,也就是说,变量基本上也就分为 两类,全局变脸和局部变量。
当然,还需要区分几个概念。外部变量,全局变量,静态变量和局部变量。
所谓的外部变量,其实是一种违反oop基本思想的应用,封装是oop的重要组成部分,将相关的类进行打包,这时封装的概念,但是外部变量,在oc中可以通过一些特殊的调用实现,在不同的文件中访问另外一个文件的变量。基本的方法是这样的,在需要访问的变量之前加上extern作为修饰,例如,classa中有一个全局变量叫做int i,我需要在main中直接调用这个变量,就可以在main中直接编写extern int i;这个时候在内存中main中的i的指针就已经指向了classa中i的值。
全局变量用在类方法声明之前,通过这样声明,在这个类中的所有方法都可以使用这个变量。
静态变量比较特殊,他很好的维护了oop思想中关于封装的概念,通过在全局变量前面加上static进行修饰,就能实现创建静态变量的目的。例如,static int i。
最后说下局部变量,有一个例子可以非常好的说明这个问题。
for (int i=0;i<100;i++){
statement;
}
i=3;
在这个例子中oc编译器是会报错的,因为这个例子中的i是一个局部变量,所谓局部变量的生存域,仅仅是这个局部变量定义的地方,也就是说当循环结束的时候,之前想内存申请的i的空间就已经释放,这个时候我们就不能向i赋值,另外一个常见的错误就是,局部变量是需要初始值的,他跟全局变量不同,全局变量在定义生成的时候就已经有了一个默认的初始值。
谈到封装,就需要探讨一下实例变量的作用域到底有什么限制,类似于java。oc中也有用来修饰作用域的关键字,分为@protected@public@private@package。
或者说我们可以做一个表来说明这些修饰符的具体作用域。
修饰符/作用域 |
当前类 |
当前包 |
派生类 |
其他包 |
@public |
true |
true |
true |
true |
@private |
true |
false |
false |
false |
@protected |
true |
true |
true |
false |
@package |
其中package我实在是理解不了,书上的原话是:对于64位图像,可以在实现该类的图像的任何地方访问这个实例变量。- -这究竟是什么意思。关人家64位图像什么事。
而java中将@package换成了@friendly并且只能在当前类和当前包中进行调用。
其中有一点需要注意的时候,在oc中可以使用const作为修饰符来修饰局部变量,从而使得这个局部变量的值变成常量,比如派这个东西。
枚举类型是一个比较使用的数据类型,当数据规模非常固定的时候,我很乐意使用这个数据类型,比如一年十二个月,一天24小时等等。格式如下:
enum flag{ jan=1,feb,mar,apr,may,jun}
通过这样就定义了一个枚举类型,其中有一月到六月。并且需要声明一个enum flag来储存可能的值,例如:
enum flag monthExample;
这个时候就可以向monthExample赋值。
需要说明的一点是,当默认的,枚举中的第一个值的参数为0,后面以此类推,当碰到特殊说明的时候,比如mar本来应该是3,但是我写成mar=5,那么mar就等于5,并且后面以这个值作为起点进行再次类推。
typedef是一个很牛逼的语句,通过这个语句的实现,可以为一系列变量添加一个名称,比如在一个程序中,i,j,k,m,n都属于计数器,那么
typedef int count;
count i,j,k,m,n;
这样在程序阅读中就能省去不少麻烦。
当然,定义的变量类型必须相同。
求纠错。