前言:为什么学习 Objective-C?
尽管现在 Apple 主推 Swift 语言,但 Objective-C 仍然是:

- 维护旧项目:大量成熟的 Apple 应用和第三方库都是用 Objective-C 编写的。
- 理解底层:学习 Objective-C 能让你更深入地理解 Objective-C Runtime,从而更好地理解 Swift 的一些底层机制和消息转发机制。
- 生态系统兼容:当你需要使用某个只有 Objective-C 版本的库时,你必须能读懂它。
第一部分:核心概念 - 从 C 到面向对象
Objective-C 是 C 语言的超集,这意味着任何合法的 C 代码都是合法的 Objective-C 代码,它在此基础上增加了 Smalltalk 风格的面向对象特性。
语法特点:消息传递 vs. 函数调用
这是理解 Objective-C 的关键。
- C/Java/C# 风格(函数调用):
[对象 函数]这种方式更像是直接调用对象的一个方法,强调“行为”。 - Objective-C 风格(消息传递):
[对象 消息: 参数]这种方式更像是给对象发送一个消息,对象收到消息后决定如何响应(即调用哪个方法),它强调“通信”。
示例:
// C 风格函数调用 int result = add(3, 5); // Objective-C 风格消息传递 NSString *greeting = @"Hello"; NSUInteger length = [greeting length]; // 给 greeting 对象发送 "length" 消息
关键字和符号
Objective-C 引入了一些独特的符号,初学者可能会感到困惑:

- 用于标记 Objective-C 特有的类型或字面量。
@interface,@implementation,@end:定义类和实现类的开始与结束。@class:向前声明一个类。@property:声明一个属性。@synthesize/@dynamic:合成或动态生成属性的 getter/setter 方法(现代 Xcode 中@synthesize通常是自动的)。@selector():获取一个方法的 SEL(方法选择器)。- 定义 NSString 字符串字面量。
@YES,@NO:定义布尔值。@16:定义 NSNumber 数值字面量。
- 指针符号,在 Objective-C 中,所有对象(如
NSString,NSArray)都通过指针来引用,所以声明对象变量时,类型名前总有一个 。 - (减号) 和 (加号):
- (实例方法):作用于类的实例(对象)上,必须先创建对象才能调用。
- (类方法):作用于类本身,无需创建实例即可调用,通常用于创建新实例或作为工具方法。
第二部分:面向对象编程
类的声明与实现
一个完整的类分为两部分:接口(声明)和实现。
a. 接口
在 .h 文件中定义,告诉编译器这个类有什么(属性和方法)。
// Person.h #import <Foundation/Foundation.h> // Apple 基础框架,必须导入 // @interface 声明一个名为 Person 的类,继承自 NSObject // NSObject 是所有 Objective-C 类的根类 @interface Person : NSObject // --- 属性 --- // @property 声明一个名为 name 的属性 // strong: 强引用,表示该属性对对象拥有所有权,ARC (自动引用计数) 会自动管理内存。 // nonatomic: 非原子性,性能更高,在多线程环境下不安全。 @property (nonatomic, strong) NSString *name; @property (nonatomic, assign) NSInteger age; // assign: 用于基本数据类型,不涉及内存管理 // --- 方法 --- // 实例方法,以 - 开头 - (void)sayHello; // 类方法,以 + 开头,用于创建新实例 + (instancetype)personWithName:(NSString *)name andAge:(NSInteger)age; @end
b. 实现
在 .m 文件中定义,告诉编译器这些属性和方法具体是如何工作的。
// Person.m
#import "Person.h" // 导入自己的头文件
@implementation Person
// @synthesize 自动为 name 属性生成 _name 成员变量和 getter/setter 方法
// (现代 Xcode 默认自动完成,可以不写)
@synthesize name = _name;
// 实现 sayHello 方法
- (void)sayHello {
// NSLog 是 Foundation 框架中的打印函数,类似于 printf
// %@ 是一个格式说明符,用于打印对象
NSLog(@"Hello, my name is %@ and I'm %ld years old.", self.name, (long)self.age);
}
// 实现 personWithName:andAge 类方法
+ (instancetype)personWithName:(NSString *)name andAge:(NSInteger)age {
// alloc: 分配内存,创建一个未初始化的 Person 对象
// init: 初始化对象
// self: 在方法内部指代当前实例(在类方法中指代当前类)
return [[self alloc] initWithName:name andAge:age];
}
// 私有的初始化方法
- (instancetype)initWithName:(NSString *)name andAge:(NSInteger)age {
// 调用父类的初始化方法
self = [super init];
if (self) {
// 初始化成员变量
_name = [name copy]; // 对字符串使用 copy 是一个好习惯,防止外部修改
_age = age;
}
return self;
}
@end
使用类
#import <Foundation/Foundation.h>
#import "Person.h" // 导入我们刚刚定义的 Person 类
int main(int argc, const char * argv[]) {
@autoreleasepool { // 自动释放池,用于管理内存
// 1. 创建 Person 对象
Person *person1 = [Person personWithName:@"Alice" andAge:30];
// 2. 调用方法
[person1 sayHello]; // 输出: Hello, my name is Alice and I'm 30 years old.
// 3. 访问属性
person1.age = 31;
NSLog(@"%@ is now %ld years old.", person1.name, (long)person1.age);
}
return 0;
}
第三部分:Foundation 框架常用类
Foundation 框架是 Objective-C 的基石,提供了大量核心数据类型和实用工具。

NSString
字符串是不可变的(一旦创建,内容不能改变)。
NSString *str1 = @"Hello"; // 字面量创建 NSString *str2 = [[NSString alloc] initWithFormat:@"World, %@", str1]; // 格式化创建 // 常用方法 NSUInteger len = str1.length; // 获取长度 BOOL hasHello = [str1 containsString:@"lo"]; // 是否包含子串 NSString *upperStr = str1.uppercaseString; // 转大写
NSMutableString
可变字符串。
NSMutableString *mutableStr = [NSMutableString stringWithString:@"Hello"]; [mutableStr appendString:@" World!"]; // 追加字符串 [mutableStr replaceCharactersInRange:NSMakeRange(6, 5) withString:@"Objective-C"]; // 替换
NSArray
不可变数组,存放对象。
NSArray *array1 = @[@"One", @"Two", @"Three"]; // 字面量创建,最常用 NSArray *array2 = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // 传统方式 // 访问元素 NSString *firstItem = array1.firstObject; // 获取第一个对象,比 objectAtIndex: 更安全 NSString *secondItem = array1[1]; // 使用下标访问 (iOS 6+) // 获取数量 NSUInteger count = array1.count;
NSMutableArray
可变数组。
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array1]; [mutableArray addObject:@"Four"]; // 添加对象 [mutableArray removeObjectAtIndex:0]; // 移除对象
NSDictionary
不可变字典,键值对存储。
NSDictionary *dict1 = @{@"name": @"Bob", @"age": @25}; // 字面量创建
NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:@"Alice", @"name", @30, @"age", nil];
// 访问值
NSString *name = dict1[@"name"]; // 通过键访问
NSMutableDictionary
可变字典。
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithDictionary:dict1]; [mutableDict setObject:@"Engineer" forKey:@"job"]; // 添加/修改键值对 [mutableDict removeObjectForKey:@"age"]; // 移除键值对
第四部分:内存管理 (Modern Objective-C with ARC)
ARC (Automatic Reference Counting) 是现代 Objective-C 的自动内存管理机制,开发者无需手动调用 retain, release, autorelease。
强引用 vs. 弱引用
strong(默认): 强引用,只要有一个强引用指向对象,对象就不会被销毁。weak: 弱引用,不增加对象的引用计数,当对象被销毁时,弱引用会自动被置为nil,主要用于避免循环引用。
循环引用示例:
@interface A : NSObject @property (nonatomic, strong) B *bObj; @end @interface B : NSObject @property (nonatomic, strong) A *aObj; @end // 当 aObj 和 bObj 互相强引用时,它们将永远不会被释放,导致内存泄漏。
解决方案:使用 weak
// 在 B.h 中 @property (nonatomic, weak) A *aObj; // 将 aObj 改为 weak 引用
@property 修饰符总结
| 修饰符 | 适用类型 | 作用 |
|---|---|---|
strong |
对象类型 | 默认值,拥有对象所有权 |
weak |
对象类型 | 不拥有所有权,用于打破循环引用 |
copy |
对象类型 (如 NSString, NSArray) | 创建一个副本,防止外部修改影响内部值 |
assign |
基本数据类型 (NSInteger, CGRect, BOOL) | 简单赋值,不涉及内存管理 |
readonly |
所有 | 只生成 getter 方法,不生成 setter |
readwrite |
所有 | 同时生成 getter 和 setter (默认) |
第五部分:块
块是 C 语言、Objective-C 和 Swift 中的匿名函数,类似于其它语言中的闭包或 Lambda 表达式,它捕获了定义时的作用域,可以在任何地方执行。
声明和使用
// 定义一个块变量,它没有参数,返回一个 NSString
NSString (^myBlock)(void) = ^{
return @"This is a block!";
};
// 调用块
NSLog(@"%@", myBlock());
// 带参数和返回值的块
NSInteger (^addBlock)(NSInteger, NSInteger) = ^(NSInteger a, NSInteger b) {
return a + b;
};
NSLog(@"%ld", (long)addBlock(10, 20));
在方法中使用块
这在异步操作(如网络请求)中非常常见。
// 定义一个使用块作为参数的方法
- (void)performTaskWithCompletion:(void (^)(NSString *result, NSError *error))completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 模拟耗时操作
[NSThread sleepForTimeInterval:2.0];
NSString *result = @"Task completed!";
NSError *error = nil;
// 在主线程中执行回调
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(result, error);
}
});
});
}
// 调用方法
[self performTaskWithCompletion:^(NSString *result, NSError *error) {
if (error) {
NSLog(@"Error: %@", error.localizedDescription);
} else {
NSLog(@"Success: %@", result); // 2秒后输出: Success: Task completed!
}
}];
总结与下一步
恭喜你,你已经掌握了 Objective-C 的基础知识!现在你可以:
- 阅读和理解 大量的开源 Objective-C 代码和 Apple 的旧版示例。
- 维护和修改 现有的 Objective-C 项目。
- 为 Swift 项目编写 Objective-C 混编代码。
下一步学习建议:
- 深入 Runtime:了解
isa指针、消息转发机制 (method swizzling)。 - Core Data:Apple 的持久化框架。
- 网络编程:使用
NSURLSession进行网络请求。 - 与 Swift 互操作:学习如何在同一个项目中混合使用 Swift 和 Objective-C。
Objective-C 的语法可能看起来有些繁琐,但它是一门非常强大和灵活的语言,深刻理解它将极大地提升你在 Apple 平台开发领域的深度和广度。
