ObjectiveC-06-循环、逻辑控制、异常处理和程序预处理

本节详细讲解下程序运行过程中的逻辑控制指令,主要有if等,但在Objective-C中添加了预编译处理指令,这是一个新的内容需要仔细研究下。这节的内容比较简单,但需要多加练习。

循环结构

在ObjC中主要有for、while和do这三种循环结构,do是do while的组合(一般不太常用),一般适合在结尾处开始执行时才用do while语句。

在循环执行代码时可搭配 break 和 continue 语句同时使用;

for

最简单的一种集合循环模式,语法结构for( int =0; condition; exp)。

//for, 除了以下常规的for写法,还有for...in操作
        int sum = 0;
        for (int n=1; n<10; n++){
            sum += n;
        }
        NSLog(@"sum is %i", sum);

//while        
        int count=1;
        while(count<=5){
            count++;
        }
//do while
       int count=1;
       do{
            count++;
       } 
       while (number<=5)       

for in

这种是一种iterator(迭代器)模式,它与上面的不同之处在于简单,缺点是不能得到循环时的索引值,需要额外定义,在ObjectiveC中很多集合类型都实现了iterator模式。

//初始多个元素的数组
NSArray *myArray = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4",nil];

//以字符串遍历
for(NSString *item in myArray ){
   NSLog(@"this is an element of myArray %@", item);
}

//2024-03-31 18:50:18.022629+0800 helloWorld[24475:1026265] 1
//2024-03-31 18:50:18.022917+0800 helloWorld[24475:1026265] 2
//2024-03-31 18:50:18.022948+0800 helloWorld[24475:1026265] 3
//2024-03-31 18:50:18.022968+0800 helloWorld[24475:1026265] 4

选择结构

选择就用字面量if关键字来表示,有如下几种格式:

  • if:一般常用于参数验证
  • if…else:双条件处理,除了A全是B
  • if …else if…else:多条件处理,除了A,B,C外全是D,如果if太多可考虑用switch来代替

if比较简单就不多举例子了,可以按上面三种模式多多练习一下。

if else if else

//**if else if else **
if ( expression1 ){

}else if( expression2 ){

}else{

}

switch

switch可接受int、char、enum。示例如下:

//**switch case**
int flag = 1;
switch(flag){
    case v1:
        break;
    case v2:
        break;
    default:
        break;
}

中断处理

主要包括:return、breadk、continue三种。这三种其实不太好起名字,暂时就叫中断吧,这几种都可用于循环和选择结构中。

return

返回,主要使用场景有两种,一种是可用于方法返回值,另一种是方法的参数验证,比如:

NSString *iftetst(int i){
    if (i<=5){//参数验证
        return NULL; 
    }
    return @"";//方法返回
}

break, continue

用于循环中断,也可以用于switch(多if其实也是循环的一种),示例代码如下:

        NSArray *myArray = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4",nil];//初始多个元素的数组


        //以字符串遍历,当遇到长度小于4的字符串时直接跳出整个循环
        for(NSString *item in myArray ){
            if(item.length<4){
                break;
            }
            NSLog(@"%@", item);
        }
        
        //以字符串遍历,当遇到长度小于4的字符串时直接跳出这次循环,继续下一个循环
        for(NSString *item in myArray ){
            if(item.length<4){
                continue;;
            }
            NSLog(@"%@", item);
        }

异常处理

Cocoa中使用NSException类来表示异常,通常在大型程序开发过程中要封装多个与业务相关的异常,这些异常都必须继承上述的NSException类。APP是否允许异常也可以在Building settings中进行设置。
在这里插入图片描述

关键字

可用的异常处理

  1. @try:定义可抛出异常的代码块
  2. @catch:捕获获常,可以存在多个
  3. @finally:无论是否抛出异常,这段代码都会执行,一般用于资源释放
  4. @throw:在代码中手动抛出异常

捕获异常

@try{
    Complex *c3 = [Complex class];
    c3.print;
}@catch(NSException *e){
    e.reason;
}@finally{
    e.reason;
}
        
2023-12-20 21:57:17.399690+0800 FractionTest[35583:5256761] +[Complex print]: unrecognized selector sent to class 0x1000087a8
2023-12-20 21:57:17.399889+0800 FractionTest[35583:5256761]  yes

抛出异常

void exceptionTest(){
    NSException *e = [NSException exceptionWithName:@"" reason:@"" userInfo:[NSNull null]];
    //方式一,通用
    @throw  e;
    //方式二,只对NSException有效
    [e raise];
}

捕获后抛出

@try{
    Complex *c3 = [Complex class];
    c3.print;
}@catch(NSException *e){
    @throw; //这里不必指定e变量
}

程序预处理

主要是为了方便代码开发、移植和兼容等场景,ObjC中固化的一些特殊代码,这些特殊代码是编译过程的一部分,会在正式程序运行之前优先处理,使用 # 来标记,且在程序文件中必须是行的第一个字母。

typedof 设置别名

如果一个类或变量名字比较长或是特殊时,为当前的数据类型指派另一个名称。 typedof定义的别名只在本类中生效,如果想设计成全局生效,可以使用#define来定义,typeof示例如下:

//原生的 int a; 变量声明可用下面两行来代替
typedof int Counter; //把原生的int关键字起了一个叫Counter的别名

Counter a;
//把系统的Number重新起了一个叫NumberObject的API
typedef Number *NumberObject;

NumberObject n1, n2, n3;
//枚举别名
typedof enum {january=1, february=2} Month;

Month m1, m2;

#define 预定义名称

预定义名称,注意预定义的值不能在程序运行过程中被修改;一般位置在#import之后,命名也建议用全大写字母。

//定义了名称TRUE值为1,之后程序中任何出现TRUE字样的地方都会被替换为1
#define TRUE 1 
gameOver = TRUE; //gameOver==1

#define EQUALS ==
if(y EQUALS 0){}

预定义的名称的值可以进行简单的运算。

#define TRUE 1 
#define A TRUE*2

gameOver = A; //gameOver==2

带自变量的宏

//如果表达式太长了,可以在行尾加一个 \ 来换行,另外这个year是一个代码中的变量
#define IS_LEAP_YEAR year%4 == 0 && year%100 != 0 || year%400 == 0
if( IS_LEAP_YEAR ) {}

//上面的方式可读性比较差,建议改成下面的方式,添加自变量,需要注意的是IS_LEAP_YEAR(y)名称和变量的括号之间没有空格
#define IS_LEAP_YEAR(y) y%4 == 0 && y%100 != 0 || y%400 == 0
if( IS_LEAP_YEAR(year) ) {}

更复杂的宏

#define MakeFract(x,y) ([[Fraction alloc] initWith: x over: y])

Fraction *myFra = MakeFract(1, 2);

一个好的实践是把上面这些宏定义在一个单独的.h文件中,然后通过 #import 来引用。

//~~CONST.h
#define TRUE 1
#define FALSE 0

//~~Front.m
#import "CONST.h"
gameOver = TRUE;

#ifdef 预编译处理

条件定义

主要包括 #ifndef、#define、 #ifdef、#else 、#endif 这几个语句,这几个语句主要用于同一套代码在不同的设备上运行时的差异化设置。可混在正常代码方法中,不限位置。一个简单的官方例子:

#ifndef Complex_h
#define Complex_h

#import <Foundation/Foundation.h>
@interface Complex : NSObject
@end

#endif /* Complex_h */

在同一个代码中可以出现多个条件块,比如NSString.h接口

#if !defined(_OBJC_UNICHAR_H_)
#define _OBJC_UNICHAR_H_
#endif

#define NS_UNICHAR_IS_EIGHT_BIT 0

NS_SWIFT_UNAVAILABLE("Use String or NSString instead.")
@interface NSSimpleCString : NSString {
@package
    char *bytes;
    int numBytes;
    
#if __LP64__
    int _unused;
#endif
}

自定义条件

自定义条件编译逻辑,比如应用的代码如下,IPAD为自定义的变量值,在程序中按如下方法使用。

- (id) initWithCoder: (NSCoder *) decoder{
    #ifdef IPAD
        NSLog(@"AAA");
    #endif
    return (self);
} 

如果想使上述代码存在意义,可采用三种运行方法:

  • 定义方式1:在某个类中定义
#define IPAD 1
  • 定义方式2:在xcode中定义,位置 Build Settings

在这里插入图片描述

  • 定义方式3:在命令行启动时定义
clang -fobjc -arc -D IPAD main.m -

#if 和 #else 条件判断

可加一些逻辑判断,比如值比较。

#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define NSMaximumStringLength (INT MAX-1)
#endif
#if IPAD>0
#define imageFile @"barHD.png"
#endif

另外一点#ifdef,其实就是#if+#defined的缩写形式,比如:

#if defined(_OBJC_UNICHAR_H_)
#if !defined(_OBJC_UNICHAR_H_)

解除定义

用于消除某些已定义的语句,比如下列代码,如果之前定义了IPAD,之后用undef消除了,则程序不会报错,但所有判断的地方全变为了false。

#undef IPAD 

至此,ObjectiveC语言的基础部分就全部讲述完了,如果能掌握这几章的内容,那么应该可以写一些稍复杂的程序了,比如计算器、数据统计、人机问答(非AI)。后续将讲述一些高级内容,这些高级内容完全是依赖基础的,需要先把基础打牢,尤其是讲到的语法和关键字。

相关推荐

  1. Swift-23-异常处理程序预处理

    2024-04-01 00:14:02       40 阅读
  2. C++ 入门02控制结构循环

    2024-04-01 00:14:02       29 阅读
  3. 05.构造程序逻辑

    2024-04-01 00:14:02       61 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-01 00:14:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-01 00:14:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-01 00:14:02       82 阅读
  4. Python语言-面向对象

    2024-04-01 00:14:02       91 阅读

热门阅读

  1. [小程序开发] 设置request封装请求参数

    2024-04-01 00:14:02       42 阅读
  2. 每日一题 --- 四数之和[力扣][Go]

    2024-04-01 00:14:02       44 阅读
  3. 解锁背包问题:C++实现指南

    2024-04-01 00:14:02       47 阅读
  4. 每日一题 第五十七期 洛谷 统计子矩阵

    2024-04-01 00:14:02       39 阅读
  5. macbook pro 2018 T2 芯片安装 archlinux 双系统

    2024-04-01 00:14:02       60 阅读
  6. 带头循环双向链表的实现

    2024-04-01 00:14:02       45 阅读
  7. 《堕落的审判》吵架台词

    2024-04-01 00:14:02       29 阅读
  8. 算法设计-杨辉三角

    2024-04-01 00:14:02       40 阅读
  9. 记 SpringBoot 使用@RequestBody 接收不到参数

    2024-04-01 00:14:02       34 阅读