Objective-C 学习笔记(四)

最近开始学习 Objective-C 夯实基础,在此处总结可以方便本人更好地整理学习内容,此文为本系列的第四篇文章,主要复习了 Objective-C中C语言特性。

关于C语言特性

关于数组

Objective-C与C语言一样允许用户定义一组有序的数据项,即数组。其操作与C语言几乎完全一致,事实上无论是函数还是数组还是变量具备良好C基础的人都不会对此感到陌生。以下为最简单的使用数组的Fibonacci代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import <Foundation/Foundation.h>

int main(int argc, char* argv[]){
@autoreleasepool {
long Fibo [30];
Fibo [0] = 1;
Fibo [1] = 1;

for (int i = 2; i < sizeof(Fibo)/sizeof(Fibo[0]); i++) {
Fibo [i] = Fibo [i-1] + Fibo [i-2];
}

for (int i = 0; i < sizeof(Fibo)/sizeof(Fibo[0]); i++) {
NSLog(@"The result of Fibonacci[%i] is %li\n",i,Fibo[i]);
}
}
return 0;
}

关于函数

默认情况下,Objective-C语言编译器假设函数返回int,除非发生以下两种情况之一:

  • 在函数被调用之前,已经在程序中定义了该函数,
  • 在遇到函数调用之前,已经声明了该函数的返回值类型。
    调用函数或方法时,作为参数传递的值将被复制到相应的形参中。使用数组时,并非将整个数组的内容复制到形参数组中,而是传递一个指针,它表示数组所在的内存地址。所以对形参数组所做的所有更改实际上都是对原始数组而不是数组的副本执行的。因此,函数或方法返回时,这些变化仍然有效。

关于块

  • 块是对C语言的一种扩展。它并未作为标准ANSI C所定义的部分,而是由 Apple 添加。
  • 块看起来更像是函数,可以给块传递参数,块也具有返回值。
  • 块定义在函数或者方法内部,并能够访问在函数或者方法范围内、块之外的任何变量,这些变量能够访问但是并不能够改变这些变量。
  • 特殊的块修改器(由块前面含有两个下画线的字符组成)能够修改块内变量的值。
  • 块的其中一个优势在于能够让系统分配给其他处理器或应用的其他线程执行。
    以下为一个处理最小公倍数的简单块演示。
1
2
3
4
5
6
7
8
9
10
int (^gcd)(int,int)=
^(int u,int v){
int temp;
while(v!= 0){
temp = u % v;
u = v;
v = temp;
}
return u;
};

关于数组指针

要将valuesPtr设为指向数组values的第–个元素的指针,可以写成:

1
valuesPtr = values;

因为Objective-C编译器将没有下标的数组名称看作是指向数组第一个元素的指针。所以,仅仅指明values而不带下标,其作用就是产生一个指向values第一个元素的指针。不需要用到地址运算符,要产生指向values首元素的指针,还有另一个等效方式,就是对数组第一个元素应用地址运算符,即

1
valuesPtr = &values(0];

将数组values第一个元素的指针存放到指针变量valuesPtr中。此时通过

1
valuesPtr += 1;

可以使其指向下一个元素,即values[1]。在Objective-C语言中,这是完全合法的表达式,并且可以用于指向任何数据类型的指针。同时比较两个指针变量的做法也是完全合法的。这在比较指向同一数组的两个指针时非常有用。比如测试指针valuesPtr的指向是否超出了包含有100个元素的数组的范围,方法是将它与指向数组最后一个元素的指针相比较。
如果valuesPtr超出了数组values的最后元素,

1
valuesPtr > &values [99]

的结果将为TRUE,反之,表达式的值为FALSE,也可将上面的表达式相应地改写为:

1
valuesPtr > values + 99

Objective-C语言中,两指针相减的结果是它们之间所包含的元素个数。这样,如果a是指向任意类型的元素数组,而b是指向同一数组中索引值更大的其他元素,那么表达式b-a
代表的就是这两个指针之间的元素个数。

关于字符串指针

在《Objective-C 程序设计 (第六版)》中给出了以下两段代码说明字符串指针的运用。

1
2
3
4
5
6
7
8
9
// 使用常规数组索引
void copyString (char to[], char from[]){
int i;

for( i = 0 ; from[i] != '\0'; ++i)
to[i] = from [i];

to[i] = '\0';
}
1
2
3
4
5
6
7
// 使用指针数组
void copystring (char *to, char *from){
for ( ; *from != '\0'; ++from,++to )
*to = *from;

*to='0';
}

很有意思的是,Objective-C语言中用到字符串就会产生指向该字符串的指针。学习过程中在程序中使用了字符串不是字符串对象,而是属于C风格的字符串,可以通过字符串的前面是否具有@字符进行区分。这两种类型不能互换。如果一个函数需要字符数组作为参数,可以将char类型的数组或c风格字符串传递给它,不能传递一个字符串对象。

关于两种语言的联系

  1. 实例变量存储在结构中:对象实际上是结构
  2. 对象变量实际上是指针:将对象变量赋给另一个对象变量时,只是简单地复制了指针,最后都指向存储在内存中的同一结构
  3. 方法是函数,消息表达式是函数调用:调用方法是在调用与接收者类相关的函数。
  4. id类型是通用指针类型:通过指针来引用对象可以自由地将它们在id变量之间来回赋值。因此返回id类型值的方法只是返回指向内存中某对象的指针。

参考

Objective-C 程序设计 (第六版)