ObjC基础语法
# 01.ObjC基础语法
# 目录介绍
- 1.1 Objective-C
- 1.1.1 ObjC简单说明
- 1.1.2 ObjC文件说明
- 1.1.3 HelloWorld
- 1.1.4 理解OC中指针
- 1.1.5 import导包介绍
- 1.1.6 ObjC相关术语
- 1.1.7 核心学习概念
- 1.2 消息传递的设计
- 1.2.1 理解消息传递
- 1.2.2 C++和OC区别
- 1.2.3 用一个案例展示
- 1.2.4 二种风格优劣
- 1.3 字符串设计和使用
- 1.3.1 字符串介绍
- 1.3.2 字符串的创建
- 1.4 基本数据的使用
- 1.4.1 常见的基础类型
- 1.4.2 常见的集合类型
- 1.4.3 NSArray
- 1.4.4 NSDictionary
- 1.5 控制结构
- 1.5.1 条件控制结构
- 1.5.2 循环控制结构
- 1.5.3 跳转控制结构
- 1.5.4 其他控制结构
# 01.Objective-C
# 1.1.1 ObjC简单说明
Objective-C,简称OC,是一种通用、高级、面向对象的编程语言。它扩展了标准的ANSI C编程语言,将Smalltalk式的消息传递机制加入到ANSI C中。当前主要支持的编译器有GCC和Clang(采用LLVM作为后端)。
Objective-C的商标权属于苹果公司,苹果公司也是这个编程语言的主要开发者。
Objective-C是C语言的严格超集。这意味着任何C语言程序不经修改就可以直接通过Objective-C编译器,
# 1.1.2 ObjC文件说明
Objective-C的原意就是在C语言主体上加入面向对象的特性。OC项目中常用的拓展名如下:
- .h 头文件。头文件包含类,类型,函数和常数的声明。
- .m 源代码文件。这是典型的源代码文件扩展名,可以包含 Objective-C 和 C 代码。
- .mm 源代码文件。带有这种扩展名的源代码文件,除了可以包含Objective-C和C代码以外还可以包含C++代码。仅在你的Objective-C代码中确实需要使用C++类或者特性的时候才用这种扩展名。
# 1.1.3 HelloWorld
学习任何一门语言之前,基本都需要做的就是编写并运行一个HelloWorld程序,对于OC而言则是如下:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
@autoreleasepool {
NSLog (@"Hello, World!");
}
return 0;
}
2
3
4
5
6
7
8
使用clang进行编译:
clang -framework Foundation hello.m -o hello
运行:
$ ./hello
2024-04-05 09:33:22.579 hello[75742:3312942] Hello, World!
2
# 1.1.4 理解OC中指针
当我们使用指针时,我们其实是在引用一个对象的地址,而不是直接使用堆 (heap) 中创建的对象,这样,当我们传递对象并且对象被改变时,由于使用的是引用,我们能够得到改变后的对象。
由于 Objective-C 是一门面向对象的语言,当我们创建一个对象时,大多数时候都应该使用指针。
# 1.1.5 import导包介绍
在 C 中使用 #include 来导入其他文件,在 OC 中使用 #import 来导入其他文件,不同点在于 #import 可以保证文件不被重复导入。
#import <Foundation/Foundation.h> 的意思是告诉编译器查找 Foundation 框架中的 Foundation.h 文件。
通过在主文件的头部使用 #import 来使用框架提供的功能。
# 1.1.6 ObjC相关术语
OC 相关的一些术语:
- 类(class):是一种表示对象类型的结构体。对象通过它的类来获取自身的各种信息,尤其是执行每个操作需要运行的代码
- 对象(object):是一种包含值和指向其类的隐藏指针的结构体
- 实例(instance):对象的另一种称呼,例如 circle 对象是 Circle 类的实例
- 消息(message):是对象可以执行的操作,用于通知对象去做什么,对象在接收到消息后将查询对应的类,以便找到正确的代码来运行
- 方法(method):为了响应消息而执行的代码
- 方法调度(method dispatcher):OC 的一种机制,用于推测执行什么方法以响应某个特定的消息,后面会有章节专门讲解 OC 方法调度机制
- 接口(interface):是类为对象提供的的特性描述
- 实现(implementation):是使接口能正常工作的代码,实际就是类的具体实现代码
# 1.1.7 核心学习概念
- 面向对象扩展:基于 C 语言的面向对象超集,添加 Smalltalk 式消息传递。
- 动态运行时:允许运行时修改类和方法(反射、方法调配)。
- 兼容性:兼容标准 C 语法,可直接嵌入 C 代码。
- 内存管理:支持手动引用计数(MRC)和自动引用计数(ARC)。
开发环境
- 工具:Xcode(IDE)、Clang(编译器)、LLDB(调试器)
- 框架依赖:Foundation(基础类库)、UIKit(iOS)、AppKit(macOS)
# 02.消息传递的设计
# 1.2.1 理解消息传递
Objective-C最大的特色是承自Smalltalk的消息传递模型(message passing),此机制与今日C++式之主流风格差异甚大。
Objective-C里,与其说对象互相调用方法,不如说对象之间互相传递消息更为精确。消息传递是一种对象之间进行通信的机制。
# 1.2.2 C++和OC区别
此二种风格的主要差异在于调用方法/消息传递这个动作。
- C++里类别与方法的关系严格清楚,一个方法必定属于一个类别,而且在编译时(compile time)就已经紧密绑定,不可能调用一个不存在类别里的方法。
- Objective-C,类别与消息的关系比较松散,调用方法视为对对象发送消息,所有方法都被视为对消息的回应。
C++里,送一个消息给对象(或者说调用一个方法)的语法如下:
obj.method(argument);
Objective-C则写成:
[obj method: argument];
注意:所有消息处理直到运行时(runtime)才会动态决定,并交由类别自行决定如何处理收到的消息。
也就是说,一个类别不保证一定会回应收到的消息,如果类别收到了一个无法处理的消息,程序只会抛出异常,不会出错或崩溃。
# 1.2.3 用一个案例展示
展示如何使用消息传递调用对象的方法:
NSString *string = @"Hello, World!";
// 使用消息传递调用方法
NSString *result = [string stringByAppendingString:@"yc"];
NSLog(@"%@", result); // 输出:Hello, World!yc
2
3
4
创建了一个NSString对象,并将其赋值为Hello, World!。然后,我们使用 stringByAppendingString:方法发送消息给string对象拼接字符串。
请注意,使用消息传递时,编译器不会进行静态类型检查,因此需要确保消息的接收者对象确实能够响应所发送的消息,否则会导致运行时错误。
# 1.2.4 二种风格优劣
C++强制要求所有的方法都必须有对应的动作,且编译期绑定使得函数调用非常快速。缺点是仅能借由virtual关键字提供有限的动态绑定能力。
Objective-C天生即具备鸭子类型之动态绑定能力,因为运行期才处理消息,允许发送未知消息给对象。可以送消息给整个对象集合而不需要一一检查每个对象的类型,也具备消息转送机制。同时空对象nil接受消息后默认为不做事,所以送消息给nil也不用担心程序崩溃。
# 1.3 字符串设计和使用
# 1.3.1 字符串介绍
作为C语言的超集,Objective-C 支持 C 语言字符串方面的约定。也就是说,单个字符被单引号包括,字符串被双引号包括。
然而,大多数Objective-C通常不使用C语言风格的字符串。反之,大多数框架把字符串传递给NSString对象。
NSString类提供了字符串的类包装,包含了所有你期望的优点,包括对保存任意长度字符串的内建内存管理机制,支持Unicode,printf风格的格式化工具,等等。
因为这种字符串使用的非常频繁,Objective-C提供了一个助记符@可以方便地从常量值创建NSString对象。
# 1.3.2 字符串的创建
// 从一个C语言字符串创建Objective-C字符串
NSString* fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];
// 使用助记符@
NSString* name = @"PANN";
NSString* line = [NSString stringWithFormat:@"Hello, %s\n", @"String"];
2
3
4
5
# 1.4 基本数据的使用
# 1.4.1 常见的基础类型
- NSInteger:用于表示整数值,根据平台的不同,其大小可能会有所变化。
- int:用于表示整数值,通常为32位。
- long:用于表示长整数值,通常为64位。
- short:用于表示短整数值,通常为16位。
- CGFloat:用于表示浮点数值,根据平台的不同,其大小可能会有所变化。
- float:用于表示单精度浮点数值,通常为32位。
- double:用于表示双精度浮点数值,通常为64位。
- BOOL:用于表示布尔值,可以是true或false。
- char:用于表示单个字符。
- enum:用于定义一组具有离散值的常量。
int age = 25;
float height = 1.75;
double pi = 3.14159;
char initial = 'A';
BOOL isStudent = YES; // BOOL 是 Objective-C 的布尔类型
2
3
4
5
# 1.4.2 常见的集合类型
- NSArray:用于表示不可变的有序集合。
- NSMutableArray:用于表示可变的有序集合。
- NSDictionary:用于表示不可变的键值对集合。
- NSMutableDictionary:用于表示可变的键值对集合。
- NSData:用于表示二进制数据。
# 1.4.3 NSArray
Objective-C 中的 NSArray 是一种常用的集合类,用于存储有序的对象集合。
NSArray *anArray = @[@1, @2L, @3.0F, @4U, @"5"];
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2];
[mutableArray addObject:@"Hello"];
[mutableArray addObject:@"World"];
[mutableArray removeObjectAtIndex:0];
NSLog(@"%@", [mutableArray objectAtIndex:0]);
2
3
4
5
6
7
# 1.4.4 NSDictionary
字典,类似于其它编程语言中的 Map 的数据类型。
NSDictionary<NSString *, NSObject *> *dictionary =
@{ @"name" : @"Objective-C", @"birth" : @1992 };
NSObject *dName = dictionary[@"name"];
NSLog(@"dictionary = %@", [dictionary description]);
2
3
4
# 1.5 控制结构
# 1.5.1 条件控制结构
if 语句,用于根据条件执行不同的代码块。
int a = 10;
if (a > 5) {
NSLog(@"a is greater than 5");
} else if (a == 5) {
NSLog(@"a is equal to 5");
} else {
NSLog(@"a is less than 5");
}
2
3
4
5
6
7
8
switch 语句,用于多条件分支选择。
int day = 3;
switch (day) {
case 1:
NSLog(@"Monday");
break;
case 2:
NSLog(@"Tuesday");
break;
case 3:
NSLog(@"Wednesday");
break;
default:
NSLog(@"Invalid day");
break;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5.2 循环控制结构
for 循环,用于重复执行代码块,通常用于已知循环次数的情况。
for (int i = 0; i < 5; i++) {
NSLog(@"i = %d", i);
}
2
3
while 循环,在条件为真时重复执行代码块。
int i = 0;
while (i < 5) {
NSLog(@"i = %d", i);
i++;
}
2
3
4
5
do-while 循环,先执行一次代码块,然后在条件为真时重复执行。
int i = 0;
do {
NSLog(@"i = %d", i);
i++;
} while (i < 5);
2
3
4
5
for-in 循环,用于遍历集合(如数组、字典等)。
NSArray *array = @[@"Apple", @"Banana", @"Orange"];
for (NSString *fruit in array) {
NSLog(@"Fruit: %@", fruit);
}
2
3
4
# 5.3 跳转控制结构
break 语句,用于立即退出循环或 switch 语句。
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 退出循环
}
NSLog(@"i = %d", i);
}
2
3
4
5
6
continue 语句,用于跳过当前循环的剩余部分,直接进入下一次循环。
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
NSLog(@"i = %d", i);
}
2
3
4
5
6
return 语句,用于从函数中返回值并退出函数。
- (int)add:(int)a to:(int)b {
return a + b;
}
2
3
# 5.4 其他控制结构
@autoreleasepool,用于管理内存,自动释放对象。
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"Hello, %@", @"World"];
NSLog(@"%@", str);
}
2
3
4
@synchronized,用于实现线程同步,确保代码块在同一时间只能被一个线程执行。
NSObject *lock = [[NSObject alloc] init];
@synchronized(lock) {
// 线程安全的代码块
}
2
3
4