杰瑞科技汇

object c 基础教程

Objective-C 基础教程

目录

  1. 引言:什么是 Objective-C?
  2. 开发环境搭建
  3. 第一个程序:Hello, World!
  4. 基础语法
    • 导入头文件
    • #import vs #include
    • 日志输出
    • 注释
  5. 数据类型
    • 基本数据类型
    • 对象类型 (id)
    • NSString (字符串)
    • NSArray (数组), NSDictionary (字典), NSNumber (数字)
  6. 核心概念:面向对象编程
    • 类与对象
    • 接口与实现
    • 实例变量
    • 属性
    • 方法
      • 实例方法
      • 类方法
    • 消息发送
  7. 内存管理
    • 手动引用计数
    • 自动引用计数 - 现代 Objective-C 的标准
  8. 协议
  9. 总结与学习资源

引言:什么是 Objective-C?

Objective-C(简称 OC)是 Apple 公司的主要编程语言,用于开发 macOS、iOS、iPadOS 和 watchOS 等平台的应用程序。

object c 基础教程-图1
(图片来源网络,侵删)

它是一门“混血”语言:

  • C 语言基础:Objective-C 是 C 语言的超集,这意味着任何合法的 C 语言代码,都可以直接在 Objective-C 中编译和运行,它拥有 C 语言的全部特性,如指针、结构体、函数等。
  • Smalltalk 消息传递:在 C 语言的基础上,Objective-C 添加了面向对象的特性,其核心是“消息传递”(Message Passing),而不是传统的“函数调用”(Function Call),这是它与 C++、Java 等语言最大的不同。

为什么学习它?

  • 开发 Apple 生态应用:如果你想开发原生的 iPhone、iPad、Mac 应用,Objective-C 是必经之路(尽管现在 Swift 更流行,但大量现有项目仍使用 OC)。
  • 理解底层:学习 OC 能让你更深入地理解 Apple 框架(如 Foundation, UIKit)的工作原理。
  • 独特的编程思想:OC 的动态特性和消息传递机制,会给你带来全新的编程视角。

开发环境搭建

现代 Objective-C 开发主要使用 Xcode,这是 Apple 官方提供的集成开发环境。

  1. 下载 Xcode:访问 Mac App Store,搜索并免费下载 Xcode。
  2. 安装:Xcode 是一个庞大的应用,安装过程可能需要一些时间和空间。
  3. 创建新项目
    • 打开 Xcode,选择 "Create a new Xcode project"。
    • 选择 "macOS" -> "Command Line Tool"。
    • 在 "Language" 选项中,选择 Objective-C
    • 给项目命名,选择一个位置,然后点击 "Create"。

Xcode 会自动为你生成一个基础的 OC 项目结构。

object c 基础教程-图2
(图片来源网络,侵删)

第一个程序:Hello, World!

Xcode 生成的项目中,通常会有一个 main.m 文件。m 是 Objective-C 源文件的标准后缀。

打开 main.m,你会看到类似这样的代码:

#import <Foundation/Foundation.h>
// int main(int argc, const char * argv[]) {
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}

代码解释:

  • #import <Foundation/Foundation.h>:导入 Foundation 框架,这个框架包含了 OC 的基本类,如 NSString, NSArray, NSObject 等,没有它,我们甚至无法使用 NSLog
  • int main(...):程序的入口点,和 C 语言一样。
  • @autoreleasepool { ... }:这是一个自动释放池,用于管理内存,我们会在后面的内存管理部分详细解释,只需知道所有需要自动管理的对象都应该放在这里。
  • NSLog(@"Hello, World!");:在控制台打印日志。 这种形式表示一个 OC 字符串对象。NSLog 会自动在输出的末尾添加时间戳和程序信息。

运行程序:点击 Xcode 左上角的播放按钮(▶️),或者按 Cmd + R,在底部的控制台窗口,你将看到输出:

object c 基础教程-图3
(图片来源网络,侵删)
2025-10-27 10:30:00.123 MyProject[12345:67890] Hello, World!

基础语法

导入头文件

  • #import <Framework/Header.h>:导入系统框架的头文件。<> 表示在系统路径下查找。
  • #import "Local/Header.h":导入你自己项目中的头文件。 表示在项目相对路径下查找。

#import vs #include

#import 是 Apple 对 C 语言 #include 的增强,它的作用和 #include 一样,都是导入文件,但 #import 会确保同一个文件只被导入一次,从而避免了重复包含导致的编译错误,在 OC 中,始终使用 #import

日志输出

除了 NSLog,你还会看到 printf(来自 C 语言)。

NSLog(@"This is an Objective-C log."); // 输出: 2025-10-27 ... This is an Objective-C log.
printf("This is a C-style log.\n");    // 输出: This is a C-style log.

区别:NSLog 更适合 OC,因为它能更好地处理对象,并附带调试信息。printf 速度稍快,但主要用于 C 风格的输出。

注释

  • 单行注释:// This is a comment
  • 多行注释:/* This is a multi-line comment */

数据类型

基本数据类型

这些和 C 语言完全一样。

  • int: 整数
  • float: 单精度浮点数
  • double: 双精度浮点数
  • char: 字符
  • BOOL: 布尔值 (YES/NO, true/false)
int age = 30;
float price = 99.9f;
BOOL isStudent = YES;

对象类型 (id)

id 是一个特殊的类型,它可以指向任何 Objective-C 对象,它是一个动态类型,编译时不会检查对象具体是什么类型,只有在运行时才会确定。

id myObject = someObject; // myObject 可以是 NSString, NSArray, 或者任何其他 OC 对象

NSString (字符串)

字符串是 OC 中最常用的对象类型之一,它使用 符号作为前缀。

// 创建字符串
NSString *greeting = @"Hello"; // 注意:* 表示 greeting 是一个指向 NSString 对象的指针
// 字符串拼接
NSString *name = @"Alice";
NSString *fullGreeting = [greeting stringByAppendingFormat:@", %@", name];
NSLog(@"%@", fullGreeting); // 输出: Hello, Alice
// 使用格式化创建字符串
NSString *anotherGreeting = [NSString stringWithFormat:@"The user is: %@", name];
NSLog(@"%@", anotherGreeting); // 输出: The user is: Alice

NSArray, NSDictionary, NSNumber

这些是 Foundation 框架中常用的集合类。

  • NSArray (有序数组):存放一组对象。

    // 创建不可变数组
    NSArray *fruits = @[@"Apple", @"Banana", @"Orange"];
    NSLog(@"First fruit: %@", fruits[0]); // 通过下标访问
    // 获取数组元素个数
    NSLog(@"Fruit count: %lu", (unsigned long)fruits.count);
  • NSDictionary (键值对字典):通过唯一的键来存储值。

    // 创建不可变字典
    NSDictionary *person = @{
        @"name": @"Bob",
        @"age": @30, // NSNumber
        @"city": @"New York"
    };
    NSLog(@"Name: %@", person[@"name"]); // 通过键访问
  • NSNumber (数字包装器):因为集合类(如 NSArray)只能存放对象,不能存放基本数据类型(如 int, float),所以需要用 NSNumber 将它们包装起来。

    NSNumber *myAge = @30; // 将 int 30 包装成 NSNumber 对象
    NSNumber *myPrice = @19.99; // 将 double 19.99 包装成 NSNumber 对象

核心概念:面向对象编程

类与对象

  • :创建对象的蓝图或模板,它定义了对象所具有的属性方法
  • 对象:类的实例,是一个具体的实体,拥有类定义的属性和方法。

接口与实现

在 OC 中,一个类的定义通常分为两个文件:

  1. .h 文件 (头文件 / Interface / 公共接口):声明类的公共部分,它告诉外界“这个类有什么”和“它能做什么”。
  2. .m 文件 (实现文件 / Implementation):实现类的具体逻辑,它告诉外界“这个类具体是怎么做的”。

示例:创建一个 Person

Person.h (接口)

#import <Foundation/Foundation.h>
// @interface ... @end 是类的声明块
// Person: NSObject 表示 Person 类继承自 NSObject
// NSObject 是几乎所有 OC 类的根类,提供了最基本的功能
@interface Person : NSObject
// 声明一个属性
// @property 编译器指令,自动生成属性的 getter 和 setter 方法
// NSString *name: 属性类型和名称
// nonatomic: 非原子性,性能更好,是现代 iOS/macOS 开发的默认选择
@property (nonatomic, copy) NSString *name;
// 声明一个方法
// - (void)sayHello; 表示这是一个实例方法
// (void) 是返回类型,sayHello 是方法名
// 没有参数的方法
- (void)sayHello;
// 带参数的方法
// (void)greet:(NSString *)greeting withName:(NSString *)name;
// 冒号后面跟着参数的类型和名称
- (void)greet:(NSString *)greeting withName:(NSString *)name;
@end

Person.m (实现)

#import "Person.h" // 导入自己的头文件
// @implementation ... @end 是类的实现块
@implementation Person
// 实现 sayHello 方法
- (void)sayHello {
    NSLog(@"Hello, my name is %@.", self.name); // self 指向当前对象本身,类似于 Java/C# 中的 this
}
// 实现 greet:withName: 方法
- (void)greet:(NSString *)greeting withName:(NSString *)name {
    NSLog(@"%@, %@!", greeting, name);
}
@end

实例变量

.h 文件中,使用 @property 声明的属性,编译器会自动在 .m 文件中生成一个对应的私有实例变量(ivar),变量名通常为 _name,你通常不需要直接访问 _name,而是通过 self.name(即属性的 getter/setter)来访问。

属性

@property 是一个强大的编译器指令,它为你自动生成:

  1. 一个私有的实例变量(如 _name)。
  2. 一个 getter 方法(- (NSString *)name)。
  3. 一个 setter 方法(- (void)setName:(NSString *)name)。

属性的特性(括号里的内容):

  • nonatomic: 非原子性,性能高。
  • strong: 强引用,表示该属性对它所指向的对象拥有所有权,当对象被赋值给这个属性时,引用计数会 +1,用于对象类型。
  • weak: 弱引用,表示该属性对它所指向的对象没有所有权,当对象被赋值给这个属性时,引用计数不变,如果对象被销毁,这个属性会自动被置为 nil,常用于 delegate 模式,以避免循环引用。
  • copy: 复制,当对象被赋值给这个属性时,会调用该对象的 copy 方法创建一个副本,属性指向这个副本,用于可变对象(如 NSMutableString),以防止外部修改影响属性内部值。
  • assign: 简单赋值,用于基本数据类型(如 int, float, BOOL)和 weak 引用的对象。

方法

  • 实例方法:以 (减号) 开头,作用于单个对象实例,必须先创建对象才能调用。

    Person *p = [[Person alloc] init];
    [p sayHello];
  • 类方法:以 (加号) 开头,作用于类本身,不需要创建实例就可以调用。

    // NSString 的类方法,创建一个空字符串
    NSString *emptyString = [NSString string];

消息发送

OC 调用方法的方式称为“消息发送”。

语法:[接收者 消息]

  • [p sayHello];:向对象 p 发送 sayHello 消息。
  • [p greet:@"Hi" withName:@"Charlie"];:向对象 p 发送一个带参数的 greet:withName: 消息,注意,方法名是 greet:withName:,而不是 greet

点语法

点语法是消息发送的一种简化形式,主要用于属性的 getter 和 setter。

  • 获取属性值(调用 getter)

    NSString *name = p.name; // 等价于 [p name]
  • 设置属性值(调用 setter)

    p.name = @"David"; // 等价于 [p setName:@"David"]

点语法不能用于普通的方法调用!p.sayHello() 是错误的,必须写成 [p sayHello]


内存管理

现代 Objective-C 默认使用 自动引用计数

核心思想:每个对象都有一个“引用计数”(Retain Count),当引用计数为 0 时,对象就会被系统自动销毁。

  • alloc, new, copy, mutableCopy:这些方法创建的对象,引用计数初始为 1。
  • strong 属性赋值、对象被添加进 NSArray/NSDictionary:对象的引用计数 +1(称为 "retain")。
  • strong 属性被赋予新值、对象从 NSArray/NSDictionary 中移除:旧对象的引用计数 -1(称为 "release")。

你不需要手动 retainrelease,编译器和运行时会自动帮你管理,你只需要遵守以下规则:

  1. 谁创建,谁释放:如果你通过 alloc, new, copymutableCopy 创建了一个对象,你就拥有它,并且有责任在不再需要时释放它(在现代 ARC 下,这通常是隐式的)。
  2. 谁 retain,谁 release:如果你通过 strong 属性或其它方式 retain 了一个对象,当不再需要时,它的引用计数会自动减少。

循环引用

这是 ARC 下最常见的内存泄漏问题,当两个或多个对象互相强引用时,它们的引用计数永远不会变为 0,导致无法被释放。

解决方案:将一方的引用改为 weak

// A.h
@property (nonatomic, strong) B *b;
// B.h
@property (nonatomic, strong) A *a; // 循环引用!

修正后

// A.h
@property (nonatomic, strong) B *b;
// B.h
@property (nonatomic, weak) A *a; // B 对 A 的引用是弱引用,打破循环

协议

协议类似于 Java 中的接口或 C++ 中的纯虚类,它定义了一组方法,但不实现这些方法,任何类都可以遵循协议,并实现协议中定义的方法。

用途:实现委托模式。

示例:一个下载器,可以通知它的代理(delegate)下载进度。

DownloadProtocol.h (协议定义)

#import <Foundation/Foundation.h>
// @protocol ... @end 定义协议
// @optional 表示该协议中的方法是可选的,遵循协议的类可以选择性实现
// @required 表示该协议中的方法是必须实现的(默认)
@protocol DownloadProtocol <NSObject>
@optional
- (void)downloadDidFinish:(NSString *)filePath;
- (void)downloadDidFailWithError:(NSError *)error;
@end

Downloader.h (使用协议的类)

#import <Foundation/Foundation.h>
#import "DownloadProtocol.h"
@interface Downloader : NSObject
@property (nonatomic, weak) id<DownloadProtocol> delegate; // delegate 必须遵循 DownloadProtocol
- (void)startDownload;
@end

Downloader.m (实现)

#import "Downloader.h"
@implementation Downloader
- (void)startDownload {
    NSLog(@"Download started...");
    // 模拟下载完成
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 检查 delegate 是否响应这个方法,避免崩溃
        if ([self.delegate respondsToSelector:@selector(downloadDidFinish:)]) {
            [self.delegate downloadDidFinish:@"/path/to/file.zip"];
        }
    });
}
@end

块是 C 语言、C++、Objective-C 和 Swift 中的一个语言特性,它允许你创建一段可以在之后执行的代码,类似于匿名函数或 lambda 表达式。

语法^ { /* code here */ }

示例:

int (^myBlock)(int, int) = ^(int a, int b) {
    return a + b;
};
int result = myBlock(5, 3);
NSLog(@"Result: %d", result); // 输出: Result: 8

块在异步编程中非常常见,例如网络请求完成后执行的回调代码。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 在后台线程执行耗时操作
    NSURL *url = [NSURL URLWithString:@"http://example.com/data.json"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程,更新 UI
        NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"Received JSON: %@", jsonString);
    });
});

总结与学习资源

  • Objective-C 是 C 语言的超集,添加了 Smalltalk 风格的面向对象特性。
  • 核心是消息传递 ([receiver message])。
  • 类分为 .h (接口).m (实现)
  • 使用 @property 简化属性和方法的声明。
  • ARC (自动引用计数) 是现代 OC 的内存管理标准,只需注意避免循环引用
  • 协议 用于定义接口,常用于委托模式
  • 是强大的代码片段,常用于异步回调。

学习资源

  • 官方文档Apple Developer Documentation (最权威,但内容较多)
  • 书籍
    • Programming with Objective-C (Apple 官方免费电子书)
    • Objective-C Programming: The Big Nerd Ranch Guide (经典入门书籍)
  • 在线教程
  • 社区
    • Stack Overflow
    • V2EX (objc 板块)

希望这份教程能帮助你顺利入门 Objective-C!

分享:
扫描分享到社交APP
上一篇
下一篇