掌握Objective-C循环语句(for、while、do-while)
Objective-C 循环语句概述
在编程的世界里,循环语句是实现重复执行特定代码块的关键工具。Objective-C 作为一门强大的面向对象编程语言,提供了三种主要的循环语句:for
循环、while
循环和 do - while
循环。这些循环语句在不同的场景下各有优劣,理解并熟练运用它们对于编写高效、简洁的代码至关重要。
循环语句的基本概念
循环语句的核心目的是让计算机重复执行一段代码,直到满足特定的条件为止。这个特定条件的判断决定了循环何时结束。在编程过程中,许多任务都具有重复性,比如遍历数组中的所有元素、对一系列数据进行相同的计算操作等,循环语句能够极大地简化这些任务的实现过程。
循环语句与程序控制流
循环语句是程序控制流的重要组成部分。程序的执行顺序通常是自上而下的,但循环语句打破了这种线性执行模式,使得程序能够根据条件反复执行特定的代码段。通过合理运用循环语句,可以实现复杂的算法和逻辑,让程序更加灵活和智能。
for
循环
for
循环的语法结构
for
循环在 Objective-C 中的语法结构如下:
for (初始化表达式; 条件表达式; 递增或递减表达式) {
// 循环体代码
}
- 初始化表达式:这部分代码在循环开始前只执行一次,通常用于初始化循环控制变量。例如,我们可以在这里声明一个整型变量并赋予初始值。
- 条件表达式:在每次循环迭代开始时,都会计算这个条件表达式的值。如果该值为
true
,则执行循环体中的代码;如果为false
,则循环结束,程序继续执行循环之后的代码。 - 递增或递减表达式:在每次循环体执行完毕后,会执行这部分代码,通常用于更新循环控制变量的值,使循环朝着结束的方向发展。
for
循环的执行流程
- 首先执行初始化表达式,初始化循环控制变量。
- 然后计算条件表达式的值。如果为
true
,进入循环体执行代码;如果为false
,循环结束。 - 执行完循环体后,执行递增或递减表达式,更新循环控制变量。
- 再次计算条件表达式的值,重复步骤 2 到 4,直到条件表达式的值为
false
。
for
循环示例
- 简单的计数循环:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 5; i++) {
NSLog(@"当前计数: %d", i);
}
}
return 0;
}
在这个例子中,我们使用 for
循环从 0 计数到 4。初始化表达式 int i = 0
声明并初始化了变量 i
为 0。条件表达式 i < 5
确保 i
的值小于 5 时循环继续执行。每次循环结束后,递增表达式 i++
将 i
的值增加 1。
- 遍历数组:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *numbers = @[@1, @2, @3, @4, @5];
for (NSUInteger i = 0; i < numbers.count; i++) {
NSLog(@"数组元素: %@", numbers[i]);
}
}
return 0;
}
这里我们创建了一个包含整数的 NSArray
。for
循环的初始化表达式 NSUInteger i = 0
初始化了索引变量 i
。条件表达式 i < numbers.count
保证索引不超过数组的长度。每次循环,递增表达式 i++
使索引值增加 1,从而遍历数组中的每个元素。
for
循环的嵌套
for
循环可以嵌套使用,即在一个 for
循环的循环体内再包含另一个 for
循环。这在处理二维数据结构(如二维数组)时非常有用。
示例代码如下:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
NSLog(@"(%d, %d)", i, j);
}
}
}
return 0;
}
在这个例子中,外层 for
循环控制行数,内层 for
循环控制列数。外层循环每执行一次,内层循环会完整执行一遍,从而输出一个 3x3 的坐标矩阵。
for
循环的高级用法
- 使用逗号运算符:在初始化表达式和递增或递减表达式中,可以使用逗号运算符来执行多个语句。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int a = 0, b = 0;
for (a = 0, b = 10; a < b; a++, b--) {
NSLog(@"a: %d, b: %d", a, b);
}
}
return 0;
}
这里在初始化表达式中,我们同时初始化了 a
和 b
两个变量,在递增或递减表达式中,同时更新了 a
和 b
的值。
- 省略部分表达式:
for
循环的三个表达式都可以省略,但分号不能省略。如果省略条件表达式,需要在循环体内手动添加跳出循环的逻辑,否则会形成无限循环。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int i = 0;
for (; i < 5;) {
NSLog(@"计数: %d", i);
i++;
}
}
return 0;
}
在这个例子中,我们将初始化表达式放在了 for
循环外部,省略了初始化表达式部分,递增表达式移到了循环体内,但条件表达式保留,这样的写法同样能实现正常的计数循环。
while
循环
while
循环的语法结构
while
循环的语法结构如下:
while (条件表达式) {
// 循环体代码
}
while
循环只有一个条件表达式。在每次循环开始前,会计算这个条件表达式的值。如果值为 true
,则执行循环体中的代码;如果为 false
,则循环结束,程序继续执行循环之后的代码。
while
循环的执行流程
- 计算条件表达式的值。
- 如果条件表达式的值为
true
,执行循环体代码。 - 循环体代码执行完毕后,再次计算条件表达式的值,重复步骤 2 和 3,直到条件表达式的值为
false
。
while
循环示例
- 简单的累加器:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int sum = 0;
int num = 1;
while (num <= 10) {
sum += num;
num++;
}
NSLog(@"1 到 10 的累加和: %d", sum);
}
return 0;
}
在这个例子中,我们使用 while
循环计算 1 到 10 的累加和。初始化变量 sum
为 0 用于存储累加结果,num
为 1 作为计数变量。条件表达式 num <= 10
确保 num
的值不超过 10 时循环继续。每次循环,将 num
的值加到 sum
中,并将 num
的值增加 1。
- 用户输入验证:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSInteger input;
while (true) {
NSLog(@"请输入一个 1 到 10 之间的整数:");
scanf("%ld", &input);
if (input >= 1 && input <= 10) {
NSLog(@"你输入了一个有效的数字: %ld", input);
break;
} else {
NSLog(@"输入无效,请重新输入。");
}
}
}
return 0;
}
这里我们使用了一个 while (true)
的无限循环,在循环体内,提示用户输入一个 1 到 10 之间的整数。如果输入的数字在有效范围内,输出提示信息并使用 break
语句跳出循环;如果输入无效,提示用户重新输入。
while
循环与 for
循环的比较
- 适用场景:
for
循环通常适用于已知循环次数的场景,比如遍历固定长度的数组。而while
循环更适用于循环次数不确定,需要根据某个条件动态决定是否继续循环的场景,如上述的用户输入验证示例。 - 代码结构:
for
循环将初始化、条件判断和变量更新集中在一处,代码结构更加紧凑,可读性较好。while
循环则更侧重于条件判断,初始化和变量更新可能在循环外部或内部的不同位置,代码结构相对灵活。
do - while
循环
do - while
循环的语法结构
do - while
循环的语法结构如下:
do {
// 循环体代码
} while (条件表达式);
do - while
循环与 while
循环类似,但有一个重要区别:do - while
循环的循环体至少会执行一次,因为条件表达式是在循环体执行完毕后才进行判断。
do - while
循环的执行流程
- 首先执行循环体代码。
- 循环体代码执行完毕后,计算条件表达式的值。
- 如果条件表达式的值为
true
,再次执行循环体代码;如果为false
,循环结束,程序继续执行循环之后的代码。
do - while
循环示例
- 简单的菜单选择:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSInteger choice;
do {
NSLog(@"请选择操作: 1. 加法 2. 减法 3. 退出");
scanf("%ld", &choice);
switch (choice) {
case 1:
NSLog(@"执行加法操作");
break;
case 2:
NSLog(@"执行减法操作");
break;
case 3:
NSLog(@"退出程序");
break;
default:
NSLog(@"无效选择,请重新输入");
break;
}
} while (choice != 3);
}
return 0;
}
在这个例子中,我们使用 do - while
循环实现了一个简单的菜单选择功能。无论用户第一次输入什么,菜单都会至少显示一次。用户选择操作后,程序根据选择执行相应的逻辑。如果用户选择 3(退出),则条件表达式 choice != 3
为 false
,循环结束,程序退出。
- 读取文件内容:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
FILE *file = fopen("test.txt", "r");
if (file != NULL) {
char buffer[100];
do {
char *result = fgets(buffer, sizeof(buffer), file);
if (result != NULL) {
NSLog(@"%s", buffer);
}
} while (!feof(file));
fclose(file);
} else {
NSLog(@"无法打开文件");
}
}
return 0;
}
这里我们使用 do - while
循环读取文件 test.txt
的内容。每次循环尝试读取一行内容到 buffer
中,如果读取成功则输出。条件表达式 !feof(file)
确保在文件未到达末尾时继续循环。由于 do - while
循环的特性,即使文件为空,循环体也会执行一次读取操作,然后根据结果判断是否继续循环。
do - while
循环与 while
循环的比较
- 执行次数:
while
循环可能一次都不执行循环体,取决于条件表达式的初始值。而do - while
循环无论条件表达式的值如何,循环体至少会执行一次。 - 应用场景:当需要先执行一次操作,然后根据操作结果决定是否继续循环时,
do - while
循环是更好的选择,如上述的菜单选择和文件读取示例。而while
循环更适用于在执行操作前需要先判断条件的场景。
循环语句中的控制语句
break
语句
break
语句用于立即终止当前循环,跳出循环体。程序将继续执行循环之后的代码。在嵌套循环中,break
语句只会终止最内层的循环。
示例代码如下:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 10; i++) {
if (i == 5) {
break;
}
NSLog(@"当前计数: %d", i);
}
NSLog(@"循环结束后执行的代码");
}
return 0;
}
在这个例子中,当 i
的值等于 5 时,break
语句被执行,循环立即终止,程序继续执行 NSLog(@"循环结束后执行的代码");
这行代码。
continue
语句
continue
语句用于跳过当前循环体中剩余的代码,直接进入下一次循环的条件判断。在嵌套循环中,continue
语句只影响当前所在的循环层。
示例代码如下:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue;
}
NSLog(@"当前奇数: %d", i);
}
}
return 0;
}
在这个例子中,当 i
是偶数时,continue
语句被执行,跳过 NSLog(@"当前奇数: %d", i);
这行代码,直接进入下一次循环的条件判断,因此只有奇数会被输出。
return
语句
return
语句不仅用于从函数中返回值,在循环语句中也可以使用。当在循环体内执行 return
语句时,会立即终止当前函数的执行,包括循环,返回到调用该函数的地方。
示例代码如下:
#import <Foundation/Foundation.h>
int sumToLimit(int limit) {
int sum = 0;
for (int i = 1; i <= limit; i++) {
if (sum + i > 100) {
return sum;
}
sum += i;
}
return sum;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int result = sumToLimit(20);
NSLog(@"累加结果: %d", result);
}
return 0;
}
在 sumToLimit
函数中,当累加和 sum
加上当前的 i
值超过 100 时,执行 return sum;
语句,不仅终止了 for
循环,还从函数中返回了当前的累加和。
循环语句的性能考虑
不同循环语句的性能差异
在大多数情况下,for
、while
和 do - while
循环在性能上并没有显著的差异。现代编译器会对这些循环进行优化,使得它们的执行效率相近。然而,在一些极端情况下,细微的性能差异可能会显现出来。
例如,在循环次数固定且较少的情况下,for
循环由于其紧凑的代码结构,编译器可能更容易进行优化,从而在性能上略胜一筹。而对于循环次数不确定且依赖复杂条件判断的情况,while
和 do - while
循环的灵活性可能更重要,性能上的差异则可以忽略不计。
优化循环性能的方法
- 减少循环体内的开销:尽量避免在循环体内执行复杂的计算或函数调用,尤其是那些不依赖循环变量的操作。可以将这些操作移到循环外部。
// 未优化的代码
for (int i = 0; i < 1000; i++) {
double result = sin(M_PI / 4) * i;
NSLog(@"结果: %f", result);
}
// 优化后的代码
double factor = sin(M_PI / 4);
for (int i = 0; i < 1000; i++) {
double result = factor * i;
NSLog(@"结果: %f", result);
}
在这个例子中,sin(M_PI / 4)
的计算不依赖于循环变量 i
,将其移到循环外部,减少了循环体内的计算开销。
- 避免不必要的内存分配:在循环体内频繁分配和释放内存会导致性能下降。尽量提前分配足够的内存空间,或者使用对象池等技术来复用对象。
// 未优化的代码
for (int i = 0; i < 1000; i++) {
NSMutableArray *array = [NSMutableArray array];
// 对 array 进行操作
// 循环结束后 array 被释放
}
// 优化后的代码
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 1000; i++) {
// 对 array 进行操作
}
这里提前创建了 NSMutableArray
对象,避免了在循环体内频繁创建和销毁对象。
- 使用合适的循环类型:根据实际需求选择合适的循环类型。如果循环次数已知,优先使用
for
循环;如果需要根据条件动态决定循环次数且可能一次都不执行循环体,使用while
循环;如果循环体至少要执行一次,使用do - while
循环。
总结循环语句的使用要点
- 理解语法和执行流程:深入理解
for
、while
和do - while
循环的语法结构和执行流程是正确使用它们的基础。掌握每个循环的特点,才能在不同场景下选择最合适的循环类型。 - 注意循环控制变量:合理初始化、更新和判断循环控制变量,确保循环能够正常结束,避免出现无限循环的情况。在嵌套循环中,要特别注意不同层次循环控制变量之间的关系。
- 结合控制语句:善于使用
break
、continue
和return
等控制语句来灵活控制循环的执行流程,实现复杂的逻辑。但要注意这些控制语句的使用范围和对程序结构的影响。 - 性能优化:在编写循环代码时,要考虑性能因素,尽量减少循环体内的开销,避免不必要的内存分配,以提高程序的执行效率。
通过熟练掌握 Objective-C 的循环语句,你将能够编写出更加高效、灵活和健壮的程序,无论是开发 iOS 应用、Mac 应用还是其他基于 Objective-C 的项目,循环语句都将是你编程过程中的得力工具。在实际编程中,不断练习和总结经验,进一步提升对循环语句的运用能力。