天天看点

Objective-C基础Objective-C基础

Objective-C基础

  • Objective-C基础
    • 基本类型
    • 变量
      • 变量的定义
      • 变量声明
      • 左值和右值
    • 常量
      • 整数文字
      • 浮点文字
      • 字符常量
      • 字符串文字
      • 定义常量
    • 运算符
      • 算术运算符
      • 关系运算符
      • 逻辑运算符
      • 按位运算符
      • 赋值运算符
      • 其他运算符:sizeof和三元运算符
      • 运算符优先级
    • 循环和条件
      • 循环
      • 条件
      • ?:运算符
    • 函数
      • 定义方法
      • 方法声明
      • 调用方法
      • 函数参数
      • 简单块声明语法
      • 简单的块实现
      • 块接受参数和返回值
      • 使用类型定义块
    • 数字
    • 数组
      • 声明数组
      • 初始化数组
      • 访问数组元素
    • 指针
      • 指针是什么?
      • 如何使用指针?
      • Objective-C NULL指针
    • 字符串
    • 结构体
      • 定义结构体
      • 访问结构成员
      • 结构体作为函数参数
      • 指向结构的指针
      • 位域
    • 预处理器
      • 预处理器示例
      • 预定义的宏
      • 预处理器运算符
        • 宏延续(`\`)
        • 字符串化(`#`)
        • 令牌粘贴(`##`)
        • defined()运算符
      • 参数化宏
    • 类型定义(typedef)
      • typedef 与 #define 区别
    • 错误处理
      • NSError
    • 命令行参数

Objective-C基础

基本类型

在Objective-C编程语言中,数据类型是指用于声明不同类型的变量或函数的扩展系统。 变量的类型决定了它在存储中占用的空间大小以及如何解释存储的位模式。

Objective-C中的类型可分为以下几类:

  1. 基本类型 ,算术类型,由两种类型组成:整数类型和浮点类型。
  2. 枚举类型 ,算术类型,用于定义只能在整个程序中分配某些离散整数值的变量。
  3. void类型 ,类型说明符void表示没有可用的值。
  4. 派生类型 ,包括指针类型、数组类型、结构类型、联合类型和、函数类型。

变量

变量是程序可以操作的存储区域的名称。 Objective-C中的每个变量都有一个特定的类型,它决定了变量内存的大小和布局; 可存储在内存中的值的范围; 以及可以应用于变量的操作集。

变量的名称可以由字母,数字和下划线(_)字符组成。 它必须以字母或下划线开头,它是区分大小写的,即:大写和小写字母是不同的变量。有以下几种基本变量类型:

  1. char ,通常它是一个八位(一个字节),这是一个整数类型。
  2. int ,机器最自然的整数大小,一般是2字节或4字节。
  3. float ,单精度浮点值。
  4. double ,双精度浮点值。
  5. void ,表示不存在类型(什么类型也不是)。

变量的定义

变量定义告诉编译器为变量创建存储的位置和数量。 变量定义指定数据类型,并包含该类型的一个或多个变量的列表,如下所示:

type variable_list;

这里,type必须是有效的Objective-C数据类型,它包括:char,w_char,int,float,double,bool或任何用户定义的对象等,variable_list可以包含一个或多个用逗号分隔的标识符名称。下面显示了一些有效的声明:

int i ,m,j;
	char a,d;
	double o;
           

第一行:int i ,m,j;声明并定义变量i,m和j; 它指示编译器创建名为i,m和j的int类型变量。

变量可以在声明时初始化(分配初始值)。 初始化程序包含一个等号,后跟一个常量表达式,如下所示:

type variable_name = value;

下面是变量声明的一些例子:

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'
           

对于没有初始化变量的定义:具有静态存储持续时间的变量用NULL隐式初始化(所有字节的值都为0); 所有其他变量的初始值未定义。

变量声明

变量声明为编译器提供了保证,即存在一个具有给定类型和名称的变量,以便编译器继续进行进一步编译,而无需完整的变量详细信息。变量声明仅在编译时有意义,编译器在链接程序时需要实际的变量声明。

当使用多个文件并在其中一个文件中定义变量时,变量声明很有用,这些文件在链接程序时可用。 使用

extern

关键字在任何地方声明变量。 虽然可以在Objective-C程序中多次声明变量,但它只能在文件,函数或代码块中定义一次。

示例尝试以下示例,变量已在顶部声明,但它们在主函数内定义和初始化:

#import <Foundation/Foundation.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {
  /* variable definition: */
  int a, b;
  int c;
  float f;

  /* actual initialization */
  a = 10;
  b = 20;

  c = a + b;
  NSLog(@"value of c : %d \n", c);

  f = 80.0/3.0;
  NSLog(@"value of f : %f \n", f);

  return 0;
}
           

编译并执行上述代码时,它将产生以下结果:

2019-06-23 17:26:12.030180+0800 myFirstApp[7107:270795] value of c : 30
2019-06-23 17:26:12.031091+0800 myFirstApp[7107:270795] value of f : 26.666666
           

同样的概念适用于函数声明,在声明时提供函数名称,并且可在其他任何位置给出其实际定义。 在下面的示例中,使用C函数进行了解释,Objective-C也支持C样式函数:

// 函数声明
int func();

int main() {
   // 调用函数
   int i = func();
}

// 函数定义
int func() {
   return 99;
}
           

左值和右值

  1. 左值 ,引用内存位置的表达式称为“左值”表达式。左值可以显示为赋值的左侧或右侧。
  2. 右值 ,-术语右值是指存储在内存中某个地址的数据值。右值是一个不能赋值给它的表达式,这意味着右值可能出现在赋值的右边但不是左边。

变量是左值,因此可能出现在赋值的左侧。 数字文字是右值,因此无法分配,也不能出现在左侧。 以下是有效的声明:

但是以下不是有效的语句,会产生编译时错误 :

常量

常量指的是程序在执行期间不会改变的固定值。这些固定值也称为文字。常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字。还有枚举常量。常量被视为常规变量,只不过它们的值在定义后无法修改。

整数文字

整数文字可以是十进制,八进制或十六进制常量。前缀指定基数或基数:十六进制为0x或0X,八进制为0,十进制为空。

整数文字也可以有一个后缀,它是U和L的组合,分别对于unsigned和long。后缀可以是大写或小写,可以按任何顺序排列。

以下是整数文字的一些示例:

212         /* 合法有效 */
215u        /* 合法有效 */
0xFeeL      /* 合法有效 */
078         /* 非法无效: 8 不是八进制数字 */
032UU       /* 非法无效: 不能重复后缀*/
           

以下是各种类型的整数文字的一些示例:

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */
           

浮点文字

浮点文字有整数部分,小数点,小数部分和指数部分。 可以以十进制形式或指数形式表示浮点文字。

在使用小数形式表示时,必须包括小数点,指数或两者,并且在使用指数形式表示时,必须包括整数部分,小数部分或两者。 带符号的指数由e或E引入。

以下是浮点文字的一些示例:

3.14159       /* 合法有效 */
314159E-5L    /* 合法有效 */
510E          /* 非法无效: 不完整的指数 */
210f          /* 非法无效: 没有小数或指数 */
.e55          /* 非法无效: 缺少整数或分数 */
           

字符常量

字符文字用单引号括起来,例如’x’,可以存储在char类型的变量中。字符文字可以是普通字符(例如,‘x’),转义序列(例如,’\t’),或通用字符(例如,’\u02C0’)。

C中有某些字符,当它们以反斜杠进行时,它们具有特殊含义,它们用于表示换行符(\n)或制表符(\t)。 在这里,有一些此类转义序列代码的列表:

转义序列 表示含义

\\

\

字符

\'

'

字符

\"

"

字符

\?

?

字符

\a

警报或铃声

\b

退格

\f

换页

\n

换行

\r

回车

\t

水平制表

\v

垂直制表

\ooo

八进制数字的一到三位数

以下是显示一些转义序列字符的示例:

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Yiibai\t.com\n\n");
   return 0;
}
           

执行上面示例代码,得到以下结果:

Yiibai    .com
           

字符串文字

字符串文字或常量用双引号

""

括起来。字符串包含与字符文字类似的字符:普通字符,转义序列和通用字符。 可以使用字符串文字将长的一行分成多行,并使用空格分隔它们。以下是字符串文字的一些示例。 这两种形式都是表示相同的字符串:

"hello, dear"
"hello, " "d" "ear"
           

定义常量

Objetive-C中有两种简单的方法来定义常量:

1.使用

#define

预处理器。

以下是使用#define预处理器定义常量的形式 :

通过以下示例代码理解 :

#import <Foundation/Foundation.h>

#define LENGTH 10   
#define WIDTH  25
#define NEWLINE '\n'

int main() {
   int area;
   area = LENGTH * WIDTH;
   NSLog(@"value of area : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-23 18:39:03.505712+0800 myFirstApp[8397:359638] value of area : 250
2019-06-23 18:39:03.505797+0800 myFirstApp[8397:359638] 
           

2.使用

const

关键字。

使用const关键字作为前缀来声明具有特定类型的常量,如下所示:

通过以下示例代码理解:

const int  LENGTH = 10;
   const int  WIDTH  = 15;
   const char NEWLINE = '\n';
   int area;  

   area = LENGTH * WIDTH;
   NSLog(@"value of area : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
           

执行上面示例代码,得到以下结果:

2019-06-23 18:42:39.597870+0800 myFirstApp[8462:364511] value of area : 150
2019-06-23 18:42:39.597953+0800 myFirstApp[8462:364511]  
           

运算符

运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 Objective-C语言内置很多运算符,提供如下类型的运算符:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 赋值运算符
  • 其它运算符

算术运算符

下表显示了Objective-C语言支持的所有算术运算符。 假设变量A=10,变量B=20,则 :

运算符 描述 示例

+

两个操作数相加

A + B = 30

-

从第一个减去第二个操作数

A - B = -10

*

两个操作数相乘

A * B = 200

/

分子除以分母

B / A = 2

%

模数运算符,整数除法后的余数

B % A = 0

++

递增运算符,将整数值增加

1

A++

,结果为

11

--

递减运算符,将整数值减

1

A--

,结果为

9

关系运算符

下表显示了Objective-C语言支持的所有关系运算符。假设变量A=10,变量B=20,则:

运算符 描述 示例

==

比较两个操作数的值是否相等; 如果相等,则条件成立。

(A == B)

结果为:

false

!=

比较两个操作数的值是否相等; 如果不相等,则条件成立。

(A != B)

结果为:

true

>

比较左操作数的值是否大于右操作数的值; 如果是,则条件成立。

(A > B)

结果为:

false

<

比较左操作数的值是否小于右操作数的值; 如果是,则条件成立。

(A < B)

结果为:

true

>=

比较左操作数的值是否大于等于右操作数的值; 如果是,则条件成立。

(A >= B)

结果为:

false

<=

比较左操作数的值是否小于等于右操作数的值; 如果是,则条件成立。

(A <= B)

结果为:

true

逻辑运算符

下表显示了Objective-C语言支持的所有逻辑运算符。 假设变量A=1,而变量B=0,则:

运算符 描述 示例

&&

逻辑“与”运算符。 如果两个操作数都不为零,则条件成立。

(A && B)

结果为:

false

||

逻辑“或”运算符。如果两个操作数中的任何一个不为零,则条件变为true。

(A || B)

结果为:

true

!

逻辑“非”运算符。 用于反转其操作数的逻辑状态。 如果条件为true,则逻辑“非”运算符后将为false。

!(A && B)

结果为:

true

按位运算符

按位运算符处理位并执行逐位运算。 &,|和^的真值表如下:

p q p

&

q
p

|

q
p

^

q
1 1 1
1 1 1 1
1 1 1

假设A = 60和B = 13,现在以二进制格式,它们按位运算将如下:

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

~A  = 1100 0011
           

Objective-C语言支持按位运算符。假设变量A=60,变量B=13,如下表所示:

运算符 描述 示例

&

进制AND运算符,如果两个操作数同位上存在1,则它会将结果复制到结果中。

(A & B) = 12

, 也就是:

0000 1100

|

二进制OR运算符,如果存在于任一操作数中,则复制1位。

(A Ι B) = 12

, 也就是:

0011 1101

^

二进制异或运算符,如果在一个操作数中设置,但不在两个操作数中设置,则复制该位。

(A ^ B) = 49

, 也就是:

0011 0001

~

二元补语运算符是一元的,具有“翻转”位的效果。

(~A )

结果为:

-61

, 也就是:

1100 0011

<<

二进制左移运算符。左操作数值向左移动右操作数指定的位数。

A << 2 = 240

, 也就是:

1111 0000

>>

二进制右移运算符。左操作数值向右移动右操作数指定的位数。

A >> 2 = 15

, 也就是:

0000 1111

赋值运算符

Objective-C语言支持以下赋值运算符:

运算符 描述 示例

=

简单赋值运算符,将右侧操作数的值分配给左侧操作数

C = A + B

是将

A + B

的值分配给

C

+=

相加和赋值运算符,它将右操作数添加到左操作数并将结果赋给左操作数

C += A

相当于

C = C + A

-=

相减和赋值运算符,它从左操作数中减去右操作数,并将结果赋给左操作数

C -= A

相当于

C = C - A

*=

相乘和赋值运算符,它将右操作数与左操作数相乘,并将结果赋给左操作数

C *= A

相当于

C = C * A

/=

除以和赋值运算符,它将左操作数除以右操作数,并将结果赋给左操作数

C /= A

相当于

C = C / A

%=

模数和赋值运算符,它使用两个操作数获取模数,并将结果赋给左操作数

C %= A

相当于

C = C % A

<<=

左移和赋值运算符

C <<= 2

相当于

C = C << 2

>>=

右移和赋值运算符

C >>= 2

相当于

C = C >> 2

&=

按位并赋值运算符

C &= 2

相当于

C = C & 2

^=

按位异或和赋值运算符

C ^= 2

相当于

C = C ^ 2

|

按位包含OR和赋值运算符

C |= 2

相当于

C = C | 2

其他运算符:sizeof和三元运算符

运算符 描述 示例

sizeof()

返回变量的大小

sizeof(a)

, 这里如果变量

a

是整数,则将返回:

4

&

返回变量的地址。

&a

将返回变量的实际地址。

*

指向变量的指针。

*a

将指向变量。

? :

条件表达式 如果条件为真?然后是

X

值:否则为

Y

值。

运算符优先级

运算符优先级确定表达式中的术语分组。这会影响表达式的计算方式。 某些运算符优先级高于其他运算符; 例如,乘法运算符的优先级高于加法运算符 -

例如,

x = 7 + 3 * 2;

这里,

x

被赋值为

13

,而不是

20

,因为

*

运算符的优先级高于

+

运算符,所以它首先计算

3 * 2

然后加上

7

此处,具有最高优先级的运算符显示在下表的顶部,具有最低优先级的运算符显示在下表底部。 在表达式中,将首先评估更高优先级的运算符。

分类 运算符 关联性
后缀

()

[]

->

.

++

--

左到右
一元

+

-

!

~

++

--

(type)*

&

sizeof

右到左
相乘

*

/

%

左到右
相加

+

-

左到右
位移

<<

>>

左到右
关系

< <=

> >=

左到右
相等

==

!=

左到右
按位XOR

^

左到右
按位OR

|

左到右
逻辑AND

&&

左到右
逻辑OR

||

左到右
条件

?:

右到左
分配

=

+=

-=

*=

/=

%=

>>=

<<=

&=

^=

|=

右到左
逗号

,

左到右

循环和条件

循环

编号 循环类型 描述
1

while

循环
在给定条件为真时重复语句或语句组,它在执行循环体之前测试条件。
2

for

循环
多次执行一系列语句,并缩写管理循环变量的代码。
3

do…while

循环

while

循环语句一样,但它在循环体的末尾测试条件。
4 嵌套循环 在任何其他循环内使用一个或多个循环,

while

for

do...while

循环。

条件

Objective-C编程语言将任何非零和非null假定为true,如果它为零或null,则将其假定为false。

编号 语句 描述
1

if

语句

if

语句是由布尔表达式后跟一个或多个语句组成。
2

if…else

语句

if

语句后面可以跟一个可选的

else

语句,该语句在

if

布尔条件表达式为

false

时执行。
3 嵌套

if

语句
在一个

if

else if

语句中可使用

if

else if

语句。
4

switch

语句

switch

语句用于测试变量与值列表的相等性。
5 嵌套

switch

语句
在一个

switch

语句中使用一个

switch

语句。

?:运算符

条件运算符可以用来替换if…else语句。它的一般形式如下:

Exp1,Exp2和Exp3都是表达式。 注意冒号的使用和放置。

?表达式的确定方式如下:评估

Exp1

。 如果结果为

true

,那么

Exp2

会被评估并成为整个值

?

表达式的值。 如果

Exp1

评估为

false

,则计算

Exp3

Exp3

的结果值将成为表达式的值。

函数

函数是一组一起执行任务的语句。 每个Objective-C程序都有一个C函数,也就是main()函数,所有最简单的程序都可以定义为函数。

可将代码划分为单独的函数。如何在不同的函数之间划分代码取决于程序员,但逻辑上这个划分通常是这样,每个函数执行一个特定的任务。

函数声明告诉编译器函数的名称,返回类型和参数。 函数定义提供函数的实际主体。

在Objective-C中,基本上会将函数称为方法。

Objective-C基础框架提供了程序可以调用的许多内置方法。 例如,appendString()方法将字符串附加到另一个字符串。已知一种方法具有各种名称,如函数或子程序或程序等。

定义方法

Objective-C编程语言中方法定义的一般形式如下:

- (return_type) method_name:( argumentType1 )argumentName1 
    joiningArgument2:( argumentType2 )argumentName2 ... 
    joiningArgumentn:( argumentTypen )argumentNamen {
    body of the function
}
           

Objective-C编程语言中的方法定义由方法头和方法体组成。 以下是方法的所有部分:

  • 返回类型, - 方法可以返回值。return_type是函数返回的值的数据类型。 某些方法执行所需的操作而不返回值。 在这种情况下,return_type是关键字void。
  • 方法名称, - 这是方法的实际名称。方法名称和参数列表一起构成方法签名。
  • 参数, - 参数就像一个占位符。调用函数时,将值传递给参数。该值称为实际参数或参数。参数列表指的是方法的参数的类型,顺序和数量。 参数是可选的; 也就是说,方法可能不包含任何参数。
  • 连接参数, - 一个连接的参数是让它更易于阅读并在调用时清楚地表达它。
  • 方法体, - 方法体包含一组语句,用于定义方法的作用。

以下是名为max()的方法的源代码。 这个方法有两个参数num1和num2,并返回两个参数的最大值:

/* 返回两个参数的最大值 */
- (int) max:(int) num1 secondNumber:(int) num2 {

   /* 局部变量声明 */
   int result;

   if (num1 > num2) {
      result = num1;
   } else {
      result = num2;
   }

   return result; 
}
           

方法声明

方法声明告诉编译器有关函数名称以及如何调用该方法的信息。 函数的实际主体可以单独定义。

方法声明包含以下部分:

- (return_type) function_name:( argumentType1 )argumentName1 
joiningArgument2:( argumentType2 )argumentName2 ... 
joiningArgumentn:( argumentTypen )argumentNamen;
           

对于上面定义的max()函数,以下是方法声明:

在一个源文件中定义方法并在另一个文件中调用该方法时,需要方法声明。 在这种情况下,应该在调用该函数的文件顶部声明该函数。

调用方法

在创建Objective-C方法时,可以定义函数必须执行的操作。 要使用方法,必须调用该函数来执行定义的任务。当程序调用函数时,程序控制将转移到被调用的方法。 被调用的方法执行已定义的任务,当执行其返回语句或达到其函数结束右括号时,它将程序控制返回给主程序。要调用方法,只需要传递必需的参数和方法名称,如果方法返回值,则可以存储返回的值。 例如:

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
/* 方法声明 */
- (int)max:(int)num1 andNum2:(int)num2;
@end

@implementation SampleClass

/* 返回两个数的最大值 */
- (int)max:(int)num1 andNum2:(int)num2 {

   /* 声明局部变量 */
   int result;

   if (num1 > num2) {
      result = num1;
   } else {
      result = num2;
   }

   return result; 
}

@end

int main () {

   /* 定义局部变量 */
   int a = 119;
   int b = 199;
   int ret;

   SampleClass *sampleClass = [[SampleClass alloc]init];

   /* 调用方法来获取最大值 */
   ret = [sampleClass max:a andNum2:b];

   NSLog(@"Max value is : %d\n", ret );
   return 0;
}
           

执行上面示例代码,得到以下结果:

函数参数

这些变量称为函数的形式参数。形式参数的行为与函数内部的其他局部变量相似,并在进入函数时创建,并在退出时销毁。在调用函数时,有两种方法可以将参数传递给函数:

调用类型 描述
按值调用 此方法将参数的实际值复制到函数的形式参数中。在这种情况中,对函数内部参数所做的更改不会对参数产生影响。
按引用调用 此方法将参数的地址复制到形式参数中。在函数内部,该地址用于访问调用中使用的实际参数。对参数所做的更改会影响参数。

默认情况下,Objective-C使用按值调用来传递参数。 所以函数内的代码改变用于调用函数的参数不会反应到函数外部,而上述示例在调用max()函数时使用相同的方法。

Objective-C类定义了一个将数据与相关行为相结合的对象。 有时,仅表示单个任务或行为单元而不是方法集合是有意义的。

块是C,Objective-C和C++等编程语言中的高级功能,它允许创建不同的代码段,这些代码段可以传递给方法或函数,就像它们是值一样。 块是Objective-C对象,因此它们可以添加到NSArray或NSDictionary等集合中。 它们还能够从封闭范围中捕获值,使其类似于其他编程语言中的闭包或lambda。

简单块声明语法

简单的块实现

returntype (^blockName)(argumentType)= ^{
};
           

下面是一个简单的示例代码:

void (^simpleBlock)(void) = ^{
   NSLog(@"This is a block");
};
           

调用上面块的示例代码:

块接受参数和返回值

块也可以像方法和函数一样获取参数和返回值。下面是一个使用参数和返回值实现和调用块的简单示例。

double (^multiplyTwoValues)(double, double) = 
   ^(double firstValue, double secondValue) {
      return firstValue * secondValue;
   };

double result = multiplyTwoValues(2,4); 
NSLog(@"The result is %f", result);
           

使用类型定义块

一个在块中使用typedef的简单示例:

#import <Foundation/Foundation.h>

typedef void (^CompletionBlock)();
@interface SampleClass:NSObject
- (void)performActionWithCompletion:(CompletionBlock)completionBlock;
@end

@implementation SampleClass

- (void)performActionWithCompletion:(CompletionBlock)completionBlock {

   NSLog(@"Action Performed");
   completionBlock();
}

@end

int main() {

   /* 第一个Objective-C程序 */
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass performActionWithCompletion:^{
      NSLog(@"Completion is called to intimate action is performed.");
   }];

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 13:27:16.212499+0800 myFirstApp[34886:1084397] Action Performed
2019-06-24 13:27:16.213305+0800 myFirstApp[34886:1084397] Completion is called to intimate action is performed.
           

数字

在Objective-C编程语言中,要以对象形式保存基本数据类型,如:int,float,bool。Objective-C提供了一系列与NSNumber一起使用的方法,一些常用重要的方法列在下表中。

编号 方法 描述
1

+ (NSNumber *)numberWithBool:(BOOL)value

创建并返回包含给定值的

NSNumber

对象,将其视为

BOOL

2

+ (NSNumber *)numberWithChar:(char)value

创建并返回包含给定值的

NSNumber

对象,将其视为

signed char

3

+ (NSNumber *)numberWithDouble:(double)value

创建并返回包含给定值的

NSNumber

对象,将其视为

double

4

+ (NSNumber *)numberWithFloat:(float)value

创建并返回包含给定值的

NSNumber

对象,将其视为

float

5

+ (NSNumber *)numberWithInt:(int)value

创建并返回包含给定值的

NSNumber

对象,将其视为

signed int

6

+ (NSNumber *)numberWithInteger:(NSInteger)value

创建并返回包含给定值的

NSNumber

对象,将其视为

NSInteger

7

- (BOOL)boolValue

BOOL

形式返回接收的值。。
8

- (char)charValue

char

形式返回接收的值。
9

- (double)doubleValue

double

形式返回接收的值。
10

- (float)floatValue

float

形式返回接收的。
11

- (NSInteger)integerValue

将接收的值作为

NSInteger

返回。
12

- (int)intValue

int

形式返回接收的值。
13

- (NSString *)stringValue

将接收的值作为人类可读的字符串形式返回。

数组

Objective-C编程语言提供了一种叫作数组的数据结构,它可以存储相同类型的固定大小顺序元素的集合。数组用于存储数据集合,但将数组视为相同类型的变量集合通常更有用。

可以声明一个数组变量(例如numbers)并使用numbers[0],numbers[1]和…,numbers[99]来表示单个变量,例如:number0,number1,…和number99,而不是声明单个变量。 使用索引来访问数组中的特定元素。

所有数组都包含连续的内存位置。 最低地址对应于第一个元素,最高地址对应于最后一个元素。

声明数组

在Objective-C中声明一个数组,程序员需要指定元素的类型和数组所需的元素数量,如下所示:

这称为一维数组。 arraySize必须是大于零的整数常量,type可以是任何有效的Objective-C数据类型。 例如,要声明一个名称为balance的double类型的10元素数组,请使用此语句:

现在,balance是一个变量数组,最多可容纳10个double类型。

初始化数组

可以逐个初始化Objective-C中的数组,也可以使用单个语句,如下所示:

大括号{}之间的值的数量不能大于在方括号[]之间为数组声明的元素的数量。以下是分配数组的单个元素的示例 -如果省略数组的大小,则会创建一个足以容纳初始化的数组。 因此,如果这样写:

这将创建与上一示例中完全相同的数组。

访问数组元素

通过索引数组名称来访问元素。通过将元素的索引放在数组名称后面的方括号中来完成的。 例如:

上面的语句将从数组中取出第10个元素,并将值赋给salary变量。 以下是一个例子,它将使用上述所有三个概念,即数组声明,分配和访问数组:

#import <Foundation/Foundation.h>

int main () {
   int n[ 10 ];   /* n 是10个整数的数组 */
   int i,j;

   /* 从 n 到 0 初始化数组的值 */         
   for ( i = 0; i < 10; i++ ) {
      n[ i ] = i + 100;    /* 从i 至 i + 100 设置数组元素的值  */
   }

   /* 输出每个数组元素的值 */
   for (j = 0; j < 10; j++ ) {
      NSLog(@"Element[%d] = %d\n", j, n[j] );
   }

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 14:06:56.692645+0800 myFirstApp[35973:1134997] Element[0] = 100
2019-06-24 14:06:56.693660+0800 myFirstApp[35973:1134997] Element[1] = 101
2019-06-24 14:06:56.693839+0800 myFirstApp[35973:1134997] Element[2] = 102
2019-06-24 14:06:56.693999+0800 myFirstApp[35973:1134997] Element[3] = 103
2019-06-24 14:06:56.694078+0800 myFirstApp[35973:1134997] Element[4] = 104
2019-06-24 14:06:56.694158+0800 myFirstApp[35973:1134997] Element[5] = 105
2019-06-24 14:06:56.694271+0800 myFirstApp[35973:1134997] Element[6] = 106
2019-06-24 14:06:56.694587+0800 myFirstApp[35973:1134997] Element[7] = 107
2019-06-24 14:06:56.694893+0800 myFirstApp[35973:1134997] Element[8] = 108
2019-06-24 14:06:56.695139+0800 myFirstApp[35973:1134997] Element[9] = 109
           

指针

使用指针可以更轻松地执行某些Objective-C编程任务,并且在不使用指针的情况下无法执行其他任务(如动态内存分配)。

每个变量都是一个内存位置,每个内存位置都定义了它的地址,可以使用符号(&)运算符进行访问,该运算符表示内存中的地址。 考虑以下示例,它将打印定义的变量的地址:

#import <Foundation/Foundation.h>

int main () {
   int  var1;
   char var2[10];

   NSLog(@"Address of var1 variable: %x\n", &var1 );
   NSLog(@"Address of var2 variable: %x\n", &var2 );

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 14:19:52.820072+0800 myFirstApp[36337:1152629] Address of var1 variable: ef4c5ee8
2019-06-24 14:19:52.820939+0800 myFirstApp[36337:1152629] Address of var2 variable: ef4c5eee
           

通过上面代码,了解了什么是内存地址以及如何访问它,到此,概念的基础知识已经结束。 接下来看看什么是指针。

指针是什么?

指针是一个变量,它的值是另一个变量的地址,即存储单元的直接地址。 与任何变量或常量一样,必须先声明指针,然后才能使用它来存储任何变量地址。 指针变量声明的一般形式是:

这里,

type

是指针的基类型; 它必须是有效的Objective-C数据类型,

var_name

是指针变量的名称。 用于声明指针的星号

*

与用于乘法的星号相同。 但是,在此语句中,星号用于将变量指定为指针。以下是有效的指针声明 :

int    *ip;    /* 指向 int 类型的指针 */
double *dp;    /* 指向 double 类型的指针 */
float  *fp;    /* 指向 float 类型的指针 */
char   *ch     /* 指向 char 类型的指针 */
           

所有指针的值是实际数据类型的地址值,无论是整数,浮点数,字符还是其他,都是相同的,是表示内存地址的长十六进制数。 不同数据类型的指针之间的唯一区别是指针指向的变量或常量的数据类型。

如何使用指针?

有一些重要的操作,经常在指针的帮助下完成。使用指针的步骤如下 -

  • 定义一个指针变量,
  • 将变量的地址赋给指针,
  • 最后访问指针变量中可用地址的值。

这是通过使用一元运算符

*

来完成的,该运算符

*

返回位于操作数指定的地址处的变量值。以下示例使用这些操作 :

#import <Foundation/Foundation.h>

int main () {
   int  var = 20;    /* 变量定义 */
   int  *ip;         /* 指针变量声明 */  
   ip = &var;       /* 在指针变量中存储 var 的地址*/

   NSLog(@"Address of var variable: %x\n", &var  );

   /* 存储在指针变量中的地址 */
   NSLog(@"Address stored in ip variable: %x\n", ip );

   /* 使用指针访问该值 */
   NSLog(@"Value of *ip variable: %d\n", *ip );

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 14:36:57.748393+0800 myFirstApp[36796:1171992] Address of var variable: e43a1ef8
2019-06-24 14:36:57.749213+0800 myFirstApp[36796:1171992] Address stored in ip variable: e43a1ef8
2019-06-24 14:36:57.749315+0800 myFirstApp[36796:1171992] Value of *ip variable: 20
           

Objective-C NULL指针

如果没有要分配的确切地址,最好将

NULL

值分配给指针变量。这是在变量声明时完成的。 指定为

NULL

的指针称为空指针。

NULL

指针是一个常量,在几个标准库中定义了零值。参考以下程序:

#import <Foundation/Foundation.h>

int main () {
   int  *ptr = NULL;
   NSLog(@"The value of ptr is : %x\n", ptr  );
   return 0;
}
           

执行上面示例代码,得到以下结果:

在大多数操作系统上,程序不允许访问地址

处的内存,因为该内存是由操作系统保留的。 但是,存储器地址

具有特殊意义; 它表示指针不是指向可访问的内存位置。 但按照惯例,如果指针包含

null

(零)值,则假定它不指向内容。

要检查空指针,可以使用if语句,如下所示:

if(ptr)     /* 如果p不为null,则成立 */
if(!ptr)    /* 如果p为null,则成立 */
           

字符串

Objective-C编程语言中的字符串使用

NSString

表示,其子类

NSMutableString

提供了几种创建字符串对象的方法。 创建字符串对象的最简单方法是使用Objective-C的标识符:

@""

来构造:

NSString *greeting = @"Hello";
NSString *siteName = @"Yiibai";
           

Objective-C支持多种操作字符串的方法,如下列表 :

编号 方法 描述
1

- (NSString *)capitalizedString;

返回接收者的大写字母表示。
2

- (unichar)characterAtIndex:(NSUInteger)index;

返回给定数组位置的字符。
3

- (double)doubleValue;

double

形式返回接收者文本的浮点值。
4

- (float)floatValue;

float

形式返回接收者文本的浮点值。
5

- (BOOL)hasPrefix:(NSString *)aString;

返回一个布尔值,指示给定字符串是否与接收者的开头字符匹配。
6

- (BOOL)hasSuffix:(NSString *)aString;

返回一个布尔值,指示给定字符串是否与接收者的结尾字符匹配。
7

- (id)initWithFormat:(NSString *)format ...;

返回通过使用给定格式字符串作为模板初始化的

NSString

对象,其余的参数值将替换到此模板中。
8

- (NSInteger)integerValue;

返回接收者文本的

NSInteger

值。
9

- (BOOL)isEqualToString:(NSString *)aString;

返回一个布尔值,该值使用基于

Unicode

的文字比较指示给定字符串是否等于接收者。
10

- (NSUInteger)length;

返回接收者中的

Unicode

字符数。
11

- (NSString *)lowercaseString;

返回接收者的小写表示。
12

- (NSRange)rangeOfString:(NSString *)aString;

查找并返回接收者中给定字符串第一次出现的范围。
13

- (NSString *)stringByAppendingFormat:(NSString *)format ...;

返回通过向接收者附加由给定格式字符串和以下参数构造的字符串而生成的字符串。。
14

- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set;

返回通过从接收器的两端移除给定字符集中包含的字符而生成的新字符串。
15

- (NSString *)substringFromIndex:(NSUInteger)anIndex;

返回一个新字符串,其中包含接收者从给定索引处的字符到结尾的字符。

结构体

Objective-C数组可定义包含多个相同类型的数据项的变量类型,但结构体是Objective-C编程中的另一个用户定义数据类型,它可组合不同类型的数据项。

结构体用于表示记录,假设要图书馆中跟踪书籍信息。可能希望跟踪每本书的以下属性:

  • 标题
  • 作者
  • 学科
  • 书名

定义结构体

要定义结构体,必须使用struct语句。 struct语句定义一个新的数据类型,为程序提供多个成员。 struct语句的格式如下所示:

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];
           

structure tag是可选的,每个成员定义是一个普通的变量定义,例如int i; 或float f;或任何其他有效的变量定义。 在结构体定义的最后,在最后一个分号之前,可以指定一个或多个结构变量,但它是可选的。以下是声明Book结构体的示例:

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
} book;
           

访问结构成员

要访问结构的任何成员,使用成员访问运算符(

.

)。成员访问运算符是结构体变量名称和要访问结构体成员之间使用句点(

.

)连接。使用

struct

关键字来定义结构类型的变量。以下是结构体用法的示例:

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};

int main() {
   struct Books Book1;        /* 声明Book类型变量:Book1 */
   struct Books Book2;        /* 声明Book类型变量:Book2 */

   /* book 1 指定值 */
   Book1.title = @"Objective-C编程";
   Book1.author = @"Yiibai"; 
   Book1.subject = @"Objective-C编程教程";
   Book1.book_id = 81234566;

   /* book 2 指定值 */
   Book2.title = @"Java编程";
   Book2.author = @"Maxsu";
   Book2.subject = @"JavaC编程教程";
   Book2.book_id = 813283488;

   /* 打印 Book1 信息 */
   NSLog(@"Book 1 title : %@\n", Book1.title);
   NSLog(@"Book 1 author : %@\n", Book1.author);
   NSLog(@"Book 1 subject : %@\n", Book1.subject);
   NSLog(@"Book 1 book_id : %d\n", Book1.book_id);

   /* 打印 Book2 信息 */
   NSLog(@"Book 2 title : %@\n", Book2.title);
   NSLog(@"Book 2 author : %@\n", Book2.author);
   NSLog(@"Book 2 subject : %@\n", Book2.subject);
   NSLog(@"Book 2 book_id : %d\n", Book2.book_id);

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 15:05:11.905928+0800 myFirstApp[37554:1213381] Book 1 title : Objective-C编程
2019-06-24 15:05:11.906706+0800 myFirstApp[37554:1213381] Book 1 author : Yiibai
2019-06-24 15:05:11.906828+0800 myFirstApp[37554:1213381] Book 1 subject : Objective-C编程教程
2019-06-24 15:05:11.906912+0800 myFirstApp[37554:1213381] Book 1 book_id : 81234566
2019-06-24 15:05:11.906998+0800 myFirstApp[37554:1213381] Book 2 title : Java编程
2019-06-24 15:05:11.907092+0800 myFirstApp[37554:1213381] Book 2 author : Maxsu
2019-06-24 15:05:11.907175+0800 myFirstApp[37554:1213381] Book 2 subject : JavaC编程教程
2019-06-24 15:05:11.907248+0800 myFirstApp[37554:1213381] Book 2 book_id : 813283488
           

结构体作为函数参数

可以将结构体作为函数参数传递,与传递任何其他变量或指针的方式非常相似。将以与上面示例中访问的方式类似,访问结构体变量如下代码:

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};

@interface SampleClass:NSObject
/* 函数声明 */
- (void) printBook:( struct Books) book ;
@end

@implementation SampleClass 

- (void) printBook:( struct Books) book {
   NSLog(@"Book title : %@\n", book.title);
   NSLog(@"Book author : %@\n", book.author);
   NSLog(@"Book subject : %@\n", book.subject);
   NSLog(@"Book book_id : %d\n", book.book_id);
}

@end

int main() {
   struct Books Book1;        /* 声明 Book类型变量 Book1 */
   struct Books Book2;        /* 声明 Book类型变量 Book2 */

   /* book 1 设置成员信息 */
   Book1.title = @"Objective-C编程";
   Book1.author = @"Yiibai"; 
   Book1.subject = @"Objective-C编程教程";
   Book1.book_id = 88774078;

   /* book 2 设置成员信息 */
   Book2.title = @"数据结构与算法";
   Book2.author = @"Max su";
   Book2.subject = @"数据结构与算法教程";
   Book2.book_id = 8899700;

   SampleClass *sampleClass = [[SampleClass alloc]init];
   /* print Book1 info */
   [sampleClass printBook: Book1];

   /* Print Book2 info */
   [sampleClass printBook: Book2];

   return 0;
}
           

执行上面示例代码,得到以下结果:

2019-06-24 15:05:11.905928+0800 myFirstApp[37554:1213381] Book 1 title : Objective-C编程
2019-06-24 15:05:11.906706+0800 myFirstApp[37554:1213381] Book 1 author : Yiibai
2019-06-24 15:05:11.906828+0800 myFirstApp[37554:1213381] Book 1 subject : Objective-C编程教程
2019-06-24 15:05:11.906912+0800 myFirstApp[37554:1213381] Book 1 book_id : 81234566
2019-06-24 15:05:11.906998+0800 myFirstApp[37554:1213381] Book 2 title : Java编程
2019-06-24 15:05:11.907092+0800 myFirstApp[37554:1213381] Book 2 author : Maxsu
2019-06-24 15:05:11.907175+0800 myFirstApp[37554:1213381] Book 2 subject : JavaC编程教程
2019-06-24 15:05:11.907248+0800 myFirstApp[37554:1213381] Book 2 book_id : 813283488
           

指向结构的指针

按照与定义指向变量的指针相似的方式来定义指向结构体的指针,如下所示:

现在,可以将结构体变量的地址存储在上面定义的指针变量中。 要查找结构变量的地址,请使用

&

运算符放在结构体名称之前,如下所示:

要使用指向结构体的指针访问结构体的成员,必须使用

->

运算符,如下所示:

使用结构体指针重新编写上面的例子:

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};

@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books *) book ;
@end

@implementation SampleClass 
- (void) printBook:( struct Books *) book {
   NSLog(@"Book title : %@\n", book->title);
   NSLog(@"Book author : %@\n", book->author);
   NSLog(@"Book subject : %@\n", book->subject);
   NSLog(@"Book book_id : %d\n", book->book_id);
}

@end

int main() {
   struct Books Book1;        /* 声明 Book 类型变量:Book1  */
   struct Books Book2;        /* 声明 Book 类型变量:Book2  */

   /* book 1 设置成员的值 */
   Book1.title = @"Objective-C编程";
   Book1.author = @"Yii Bai"; 
   Book1.subject = @"Objective-C编程教程";
   Book1.book_id = 6495407;

   /* book 2 设置成员的值 */
   Book2.title = @"数据结构与算法";
   Book2.author = @"Max Su";
   Book2.subject = @"数据结构与算法教程";
   Book2.book_id = 6495700;

   SampleClass *sampleClass = [[SampleClass alloc]init];
   /* print Book1 info by passing address of Book1 */
   [sampleClass printBook:&Book1];

   /* print Book2 info by passing address of Book2 */
   [sampleClass printBook:&Book2];

   return 0;
           

执行上面示例代码,得到以下结果:

2019-06-24 15:21:08.246394+0800 myFirstApp[37987:1236201] Book title : Objective-C编程
2019-06-24 15:21:08.247088+0800 myFirstApp[37987:1236201] Book author : Yii Bai
2019-06-24 15:21:08.247191+0800 myFirstApp[37987:1236201] Book subject : Objective-C编程教程
2019-06-24 15:21:08.247282+0800 myFirstApp[37987:1236201] Book book_id : 6495407
2019-06-24 15:21:08.247353+0800 myFirstApp[37987:1236201] Book title : 数据结构与算法
2019-06-24 15:21:08.247428+0800 myFirstApp[37987:1236201] Book author : Max Su
2019-06-24 15:21:08.247533+0800 myFirstApp[37987:1236201] Book subject : 数据结构与算法教程
2019-06-24 15:21:08.247611+0800 myFirstApp[37987:1236201] Book book_id : 6495700
           

位域

位字段允许在结构中打包数据。当内存或数据存储非常宝贵时,这尤其有用。 下面是一个典型例子:

  • 将多个对象打包成机器字。 例如 可以压缩

    1

    位标志。
  • 读取外部文件格式 - 可以读入非标准文件格式。

    9

    位整数。

Objective-C允许通过在变量之后放置:长度 来在结构定义中执行此操作。 例如:

struct packed_struct {
   unsigned int f1:1;
   unsigned int f2:1;
   unsigned int f3:1;
   unsigned int f4:1;
   unsigned int type:4;
   unsigned int my_int:9;
} pack;
           

这里,

packed_struct

包含6个成员:四个

1

位标志

f1..f3

,

4

位类型和

9

my_int

Objective-C尽可能紧凑地自动打包上述位字段,前提是字段的最大长度小于或等于计算机的整数字长。 如果不是这种情况,那么一些编译器可能允许字段的存储器重叠,而其他编译器将下一个字段存储在下一个字中。

预处理器

Objective-C预处理器不是编译器的一部分,而是编译过程中的一个单独步骤。 简单来说,Objective-C预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行必要的预处理。 我们将Objective-C预处理器称为OCPP。

有预处理器命令都以井号(

#)

开头。它必须是第一个字符(前面不能有空格),并且为了便于阅读,预处理器指令应该从第一列开始。 以下部分列出了所有重要的预处理程序指令:

编号 指令 描述
1

#define

替换预处理器宏
2

#include

从另一个文件插入特定标头
3

#undef

未定义的预处理器宏
4

#ifdef

如果定义了此宏,则返回

true

5

#ifndef

如果未定义此宏,则返回

true

6

#if

测试编译时条件是否为

true

7

#else

#if

的替代方案
8

#elif

#else

#if

中的一个语句
9

#endif

结束预处理器条件
10

#error

stderr

上打印错误消息
11

#pragma

使用标准化方法向编译器发出特殊命令

预处理器示例

分析以下示例以了解各种宏的指令。

该指令告诉OCPP 用

20

替换

MAX_ARRAY_LENGTH

宏标识。使用

#define

定义常量来提高可读性。

#import <Foundation/Foundation.h>
#include "myheader.h"
           

这些指令告诉OCPP 从

Foundation Framework

获取

foundation.h

,并将文本添加到当前源文件中。 下一行告诉OCPP 从本地目录获取

myheader.h

并将内容添加到当前源文件。

#undef  FILE_SIZE
#define FILE_SIZE 42
           

它告诉OCPP 取消定义现有的

FILE_SIZE

,并将

FILE_SIZE

定义为

42

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif
           

它告诉OCPP仅在尚未定义

MESSAGE

宏时才定义

MESSAGE

#ifdef DEBUG
   /* Your debugging statements here */
#endif
           

它告诉OCPP如果定义了

DEBUG

,则执行包含语句的过程。 如果在编译时将-

DDEBUG

标志传递给

gcc

编译器,这将非常有用。 它将定义

DEBUG

,因此可以在编译期间动态打开和关闭调试。

预定义的宏

ANSI C定义了许多宏。虽然每个都可用于编程,但不应直接修改预定义的宏。

编号 描述
1

__DATE__

当前日期为

“MMM DD YYYY”

格式的字符文字
2

__TIME__

当前时间作为

“HH:MM:SS”

格式的字符文字
3

__FILE__

它包含当前文件名作为字符串文字。
4

__LINE__

它包含当前行号作为十进制常量。
5

__STDC__

当编译器符合ANSI标准时,定义为

1

预处理器运算符

Objective-C预处理器提供以下运算符来创建宏:

宏延续(

\

)

宏通常必须包含在一行中。宏延续运算符用于继续对于单行来说太长的宏。 例如:

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")
           

字符串化(

#

)

字符串化或数字符号运算符(

#

)在宏定义中使用时,将宏参数转换为字符串常量。 此运算符只能在具有指定参数或参数列表的宏中使用。 例如:

#import <Foundation/Foundation.h>

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}
           

执行上面示例代码,得到以下结果:

令牌粘贴(

##

)

宏定义中的令牌粘贴运算符(

##

)组合了两个参数。 它允许将宏定义中的两个单独的标记连接到一个标记中。 例如 :

#import <Foundation/Foundation.h>

#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;

   tokenpaster(34);
   return 0;
}
           

执行上面示例代码,得到以下结果:

defined()运算符

预处理器定义的运算符用于常量表达式,以确定是否使用

#define

定义标识符。如果定义了指定的标识符,则该值为true(非零)。 如果未定义符号,则值为false(零)。 定义的运算符指定如下:

#import <Foundation/Foundation.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   NSLog(@"Here is the message: %s\n", MESSAGE);  
   return 0;
}
           

执行上面示例代码,得到以下结果:

参数化宏

OCPP的一个强大功能是使用参数化宏模拟函数的能力。 例如,可能需要一些代码来对数字进行平方,如下所示 :

int square(int x) {
   return x * x;
}
           

可以使用宏重写上面的代码,如下所示:

必须先使用

#define

指令定义带参数的宏,然后才能使用它们。 参数列表括在括号中,并且必须紧跟宏名称。 宏名称和左括号之间不允许有空格。 例如:

#import <Foundation/Foundation.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}
           

执行上面示例代码,得到以下结果:

类型定义(typedef)

bjective-C编程语言提供了一个名称为

typedef

的关键字,可以使用此关键字为类型指定新名称。 以下是为单字节数字定义术语

BYTE

的示例:

在此类型定义之后,标识符

BYTE

可以用作

unsigned char

类型的缩写(或别名),例如:

typedef unsigned char BYTE;
BYTE  b1, b2;
           

按照惯例,大写字母用于这些定义,以提醒用户类型名称实际上是符号缩写,但可以使用小写,如下所示:

也可以使用

typedef

为用户定义的数据类型指定名称。 例如,使用带结构的

typedef

来定义新的数据类型,然后使用该数据类型直接定义结构变量,如下所示:

#import <Foundation/Foundation.h>

typedef struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int book_id;
} Book;

int main() {
   Book book;
   book.title = @"Objective-C编程";
   book.author = @"Yiibai";
   book.subject = @"编程教程";
   book.book_id = 10010;

   NSLog( @"Book title : %@\n", book.title);
   NSLog( @"Book author : %@\n", book.author);
   NSLog( @"Book subject : %@\n", book.subject);
   NSLog( @"Book Id : %d\n", book.book_id);

   return 0;
}
           

typedef 与 #define 区别

#define

是一个Objective-C指令,它也用于定义类似于

typedef

的各种数据类型的别名,但有以下区别:

  • typedef

    仅限于为类型提供符号名称,而

    #define

    也可用于定义值的别名,比如可以将

    1

    定义为

    ONE

    等。
  • typedef

    解释由编译器执行,其中

    #define

    语句由预处理器处理。

以下是

#define

的最简单用法:

#import <Foundation/Foundation.h>

#define TRUE  1
#define FALSE 0

int main( ) {
   NSLog( @"Value of TRUE : %d\n", TRUE);
   NSLog( @"Value of FALSE : %d\n", FALSE);

   return 0;
}
           

错误处理

在Objective-C编程中,错误处理由

Foundation

框架中提供的

NSError

类提供处理。

与仅使用错误代码或错误字符串相比,

NSError

对象封装了更丰富且更具可扩展性的错误信息。

NSError

对象的核心属性是错误域(由字符串表示),特定于域的错误代码和包含应用程序特定信息的用户信息字典。

NSError

Objective-C程序使用

NSError

对象来传达有关用户需要了解的运行时错误的信息。 在大多数情况下,程序会在对话框或工作表中显示此错误信息。 但它也可能会解释信息并要求用户尝试从错误中恢复或尝试自行更正错误

NSError

对象包括:

  • 域 - 错误域可以是预定义的

    NSError

    域之一,也可以是描述自定义域和域的任意字符串,不能为

    nil

  • 代码 - 错误的错误代码。
  • 用户信息 - 错误和userInfo的字典可能为

    nil

以下示例代码显示如何创建自定义错误:

NSString *domain = @"com.yiibai.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to complete the process", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
NSError *error = [NSError errorWithDomain:domain code:-101 userInfo:userInfo];
           

以下是作为对指针的引用传递的上述错误示例的完整代码:

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr;
@end

@implementation SampleClass

-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr {
   if(id == 1) {
      return @"Employee Test Name";
   } else {
      NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
      NSString *desc =@"Unable to complete the process";
      NSDictionary *userInfo = [[NSDictionary alloc] 
      initWithObjectsAndKeys:desc,
      @"NSLocalizedDescriptionKey",NULL];  
      *errorPtr = [NSError errorWithDomain:domain code:-101 
      userInfo:userInfo];
      return @"";
   }
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   SampleClass *sampleClass = [[SampleClass alloc]init];
   NSError *error = nil;
   NSString *name1 = [sampleClass getEmployeeNameForID:1 withError:&error];

   if(error) {
      NSLog(@"Error finding Name1: %@",error);
   } else {
      NSLog(@"Name1: %@",name1);
   }

   error = nil;
   NSString *name2 = [sampleClass getEmployeeNameForID:2 withError:&error];

   if(error) {
      NSLog(@"Error finding Name2: %@",error);
   } else {
      NSLog(@"Name2: %@",name2);
   }

   [pool drain];
   return 0; 
}
           

在上面的例子中,如果id为1,则返回一个名称,否则设置用户定义的错误对象。

命令行参数

执行时,可以将一些值从命令行传递给Objective-C程序。 这些值称为命令行参数,很多时候它们对程序很重要,特别是当想要从外部控制程序而不是在代码中对这些值进行硬编码时就很有用了。

命令行参数使用

main()

函数参数处理,其中

argc

表示传递的参数数量,

argv[]

是指针数组,指向传递给程序的每个参数。 以下是一个简单的示例,它检查命令行是否提供了任何参数并采取相应的操作:

#import <Foundation/Foundation.h>

int main( int argc, char *argv[] ) {
   if( argc == 2 ) {
      NSLog(@"The argument supplied is %s\n", argv[1]);
   } else if( argc > 2 ) {
      NSLog(@"Too many arguments supplied.\n");
   } else {
      NSLog(@"One argument expected.\n");
   }
}
           

当使用单个参数编译和执行上述代码时,例如使用命令行参数“testing”,它会产结果:

$./main testing
2018-11-15 22:59:51.283 main[79514] The argument supplied is testing
           

当使用两个参数(例如

testing1

testing2

)编译和执行上述代码时,它会产生以下结果

$./main testing testing2
2018-11-15 22:59:51.283 main[79514] Too many arguments supplied.
           

当编译并执行上述代码而不传递任何参数时,它会产生以下结果.

$./main testing testing2
2018-11-15 22:59:51.283 main[79514] One argument expected
           

应该注意的是,

argv [0]

保存程序本身的名称,

argv [1]

是指向提供的第一个命令行参数的指针,而

* argv [n]

是最后一个参数。 如果没有提供参数,

argc

的值将为1,否则如果传递一个参数,则

argc

设置为2。

传递由空格分隔的所有命令行参数,但如果参数本身有空格,则可以通过将这些参数放在双引号(

""

)或单引号(

''

)中来传递这些参数。再次重写上面的例子,将打印程序名称,也通过放入双引号传递命令行参数:

#import <Foundation/Foundation.h>

int main( int argc, char *argv[] ) {
   NSLog(@"Program name %s\n", argv[0]);

   if( argc == 2 ) {
      NSLog(@"The argument supplied is %s\n", argv[1]);
   } else if( argc > 2 ) {
      NSLog(@"Too many arguments supplied.\n");
   } else {
      NSLog(@"One argument expected.\n");
   }

   return 0;
}
           

当上面的代码被编译并执行时,一个参数用空格分隔,但在双引号中是

"Testing1 Testing2"

,它会产生以下结果。

2018-11-15 23:05:06.113 main[66421] Program name main
2018-11-15 23:05:06.115 main[66421] One argument expected.
           
参考引用:https://www.yiibai.com/objective_c