基本语法
大体与 C 相同,包括 main 函数作为入口函数,main 函数的 int 和 char 数组参数,分号分割语句,花括号区分代码块等
一、语句与表达式
- 语句是用于执行某一操作的代码行,不具有返回值,不会改变当前执行代码的状态
- 表达式是具有返回值的代码行,可以改变程序流
1. 声明变量
声明变量格式:变量类型 + 变量名
变量类型可以分为
- 标量
- 指针
- 结构体
变量可以以栈帧作为作用域,具体边界由花括号确定,也就是所谓的代码块。
int aVariable = 1234
这样定义的变量实际内存空间分配在栈中,因此会在栈被释放后自动被释放。
同样的,变量也可以由应用程序主动分配在堆中,这样变量将由应用程序管理其内存空间的生命周期
SomeClass *aVariable = [[someClass alloc] init];
[aVariable release] //释放内存空间
所有内存分配在堆上的变量都视为指针,与 C 类似,用 * 号标示。但也有指针的内存空间是分配在栈上的。
2. 变量类型
标量
标量类似于“基本类型”,是指只能存储一个值的变量。
结构体
结构体用 struct 修饰,与 C 中的结构体基本类似。
简答的结构体定义
struct Point
{
float x;
float y;
}
复合结构体定义
struct Animal
{
struct Position;
struct property;
}
定义结构体只是定义了结构体的成员变量和结构体的名称,而使用一个结构体来声明一个变量有两种方式
-
直接利用 struct 关键字和结构体名称
struct Point p; p.x = 20.0; p.y = 10.0;
-
利用类型定义
typedef struct { float x; float y; } Point; Point p;
这里由于可以用 Point 代替 struct 和类型名,因此采用了匿名结构体的实现方式。
指针
指针是一个包含另一个变量地址的变量,基本操作等同于 C 语言中的指针。
声明指针
int x = 5;
int * y = &x;
在声明指针时,* 号代表当前变量为指针变量,& 取当前变量的地址值。
对指针取值
NSLog(@"X:%ld - Y:%ld", x, *y);
在使用指针或对指针取值时,* 号对当前指针变量取值。
3. 特殊变量修饰符
特殊变量修饰符主要有
- auto——局部变量生命周期与变量作用域保持一致,不建议显式使用
- static——在声明变量时分配内存并且在程序运行期间只分配一次内存
- const——修饰的变量为只读变量,即初始化后无法二次修改
- register——提示编译器所修饰变量会被频繁访问,不建议使用
- extern——表示所定义的函数或声明的变量引用了应用程序的另一个编译单元中定义或者分配的实际变量或函数
默认不带任何修饰符的变量是由 auto 修饰的。
static 的特点是全局内存唯一,类似于全局变量,但是当用 static 修饰全局变量时,全局变量将只能在声明该变量的文件内访问该变量。而通常,全局变量作用域是程序的人和地方。
4. 枚举enum
枚举是自定义数据类型的一种,用于存储一个有限的可能值列表,可以作为参数和返回值。
enum Color
{
Red,
Yellow,
Blue
};
enum Color red = Red;
当然也可以用类型定义 typedef 来简化过程。
typedef enum
{
Red,
Yellow,
Blue
}Color;
Color red = Red;
枚举在没有初始化情况下默认是整型,值依次为0,1,2。初始化枚举如下所示
typedef enum
{
Red = 20,
Green = 30,
Blue= 40
}Color;
二、函数
函数基本用法与 C 类似,要注意传递指针参数时对内存的修改问题,尤其是当指针变量作为返回值时,容易因为函数内部的变量已经被释放而导致异常的访问问题。
通常大部分函数都有一个返回值,在函数体内我们用 return 语句来返回与函数签名中对应的返回类型一致的返回值,要注意,retrun 返回语句的最佳实践是在一个函数体内只有最末尾一行使用 return 语句,这样可以保证函数体的返回值不会难以控制。
实现与接口
可以将一类函数放入一个集合中,这样一个集合称为单元,单元一般含有两部分,函数定义与函数声明
- 函数声明——声明函数的签名,不含实际定义,可以理解为接口,文件后缀为 .h
- 函数定义——实际编写函数代码,可以理解为实现,文件后缀为 .c
同时要声明一个可以在其他单元使用的函数,就需要特殊修饰符 extern 来修饰该函数。
extern int calculateFactorial(int value);
此时可以在其他单元中通过导入相应函数的接口文件 .h 来使用这一个接口函数
#import "main.h"
int main(int argc, const char * argv[])
{
int s = calculateFactorial(10);
NSLog(@"s = %d", s);
}
这里在导入文件时要注意,尖括号<>用来导入系统路径下的接口文件,而引号是导入项目当前目录及其子目录下的接口文件。
三、控制程序流
一般意义上的编程语言的程序流可以大致分为三类,顺序执行,条件执行和循环执行,顺序执行是最一般的形式。
条件执行
1. if-else 语句
int target = 10;
if (target < 5)
{
}
else if (target > 5 && target < 10)
{
}
else
{
}
2. switch语句
int flag = 0;
switch (flag) {
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
要注意的是,这里 switch 的判断条件必须是整型表达式,所以不支持字符串的多分支判断。
循环
编程语言中最常见的循环大致有 for,do while,while 三种,在 objective-c 中都有,但基于快速枚举的特性,for 循环应当作为循环首选。
1. for 循环
普通的 for 循环大致长这样
for (int i = 0; i < 100; i++)
{
NSLog(@"%d", i);
}
而 for 循环快速枚举大致为
for (Foo *object in myArray)
{
}
2. while 循环
int x = 0;
while(x < 10)
{
NSLog(@"%d", x);
x++;
}
3. do-while 循环
int x = 0;
do
{
NSLog(@"%d", x);
x++;
}
while (x < 10);
do-while 保证程序一定会执行至少一次循环体,这是与 while 循环的区别。