Objective-C:语言的本质及其在iOS开发中的地位

作者: IT Sectr 发布日期: 2026-02-09 阅读时间: 8 分钟

Objective-C — 一种具有动态消息分发的编程语言,由Brad Cox于20世纪80年代创建。Apple选择Objective-C作为NeXTSTEP的主要语言,随后用于iOS SDK。Programming With Objective-C — 消息语法和内存管理入门。

要点

  • Objective-C — C的严格超集,具有方括号中的消息语法和动态运行时
  • Message passing — 通过[object selector:argument]调用方法,通过objc_msgSend动态查找实现
  • Categories — 无需继承和无需访问源代码即可向现有类添加方法的机制
  • Blocks — 带有闭包的匿名函数,Swift闭包的前身
  • ARC vs MRC — 用于内存管理的自动和手动引用计数

什么是Objective-C?

Objective-C — 一种用Smalltalk风格面向对象编程功能扩展C的编程语言。Objective-C代码通过LLVM或GCC编译为本地机器码,同时保持与C的完全向后兼容性——任何C代码在Objective-C中都是正确的。

Apple于1997年收购了NeXT(连同Objective-C)。该语言成为Cocoa和Cocoa Touch(macOS和iOS的框架)的基础。自2014年起,Apple推广Swift作为替代,但Objective-C对于遗留项目和某些系统框架仍然至关重要。根据Apple(WWDC 2024),App Store中约35%的应用仍然包含Objective-C代码。

关键特性——动态运行时。与Swift在编译阶段解析方法调用不同,Objective-C在执行期间通过objc_msgSend函数发送消息。这允许动态覆盖方法(method swizzling)、动态添加类以及为不存在的选择器使用forward invocation。

语法:C + 对象层

任何C代码在Objective-C中都是正确的。对象层添加了类(@interface/@implementation)、类别、协议(@protocol)和动态类型(id)。文件扩展名为.m(实现)和.h(头文件)。

消息语法和动态分发

消息语法 — Objective-C与类C语言的主要区别。使用[object method:argument]代替object.method(argument)。每条消息通过objc_msgSend传递,该函数在运行时动态查找方法的实现。

objective-c
// 具有命名参数的消息语法
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];

// 嵌套消息
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];

// 通过内省进行类型检查
if ([object isKindOfClass:[UIView class]]) {
    UIView *view = (UIView *)object;
    view.backgroundColor = [UIColor redColor];
}

动态分发(Dynamic dispatch)允许在运行时覆盖方法(method swizzling)——这是一种强大但危险的技术。例如,AFNetworking和Aspects等框架使用swizzling来拦截URLSession调用。Apple警告:如果使用不当,swizzling可能会破坏系统框架的运行。

类别和类扩展

类别(Categories) — Objective-C的一项独特能力,无需继承和无需访问源代码即可向现有类(包括系统类,如NSString和UIView)添加方法。类别通过@interface ClassName (CategoryName)声明。

objective-c
// UIColor+Hex.h文件 — UIColor的类别
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end

// UIColor+Hex.m文件 — 实现
@implementation UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex {
    CGFloat r = ((hex >> 16) & 0xFF) / 255.0;
    CGFloat g = ((hex >> 8) & 0xFF) / 255.0;
    CGFloat b = (hex & 0xFF) / 255.0;
    return [self colorWithRed:r green:g blue:b alpha:1.0];
}
@end

扩展(Extensions)(类扩展)— 一种特殊类型的类别,在.m文件中匿名声明:@interface ClassName ()。与类别不同,扩展不仅可以添加方法,还可以添加ivar(实例变量)和属性。扩展用于对外部模块隐藏内部API。

块(Blocks)——带有闭包的匿名函数

块(Blocks) — Objective-C中的匿名函数,捕获外部作用域中的变量。块语法:^(int x) { return x * 2; }。块在UIKit中用于回调处理程序,在Grand Central Dispatch中用于异步任务,在NSArray/NSDictionary集合中用于函数式操作。

objective-c
// 块类型的声明
typedef void (^CompletionBlock)(BOOL success, NSError *error);

// 块作为参数
- (void)fetchDataWithCompletion:(CompletionBlock)completion {
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        BOOL result = [weakSelf processData];
        if (completion) {
            completion(result, nil);
        }
    });
}

块中的内存管理至关重要。块使用强引用捕获self,在直接使用时会造成保留循环。解决方案——__weak typeof(self) weakSelf = self,并在块内部进行后续检查。这个问题在Swift中通过捕获列表[weak self]完全解决。

ARC和MRC:内存管理

Objective-C经历了从MRC(手动引用计数)ARC(自动引用计数)的历程。在MRC中,程序员手动调用retain(增加计数器)、release(减少)和autorelease(延迟释放)。这些调用中的错误会导致内存泄漏或因悬空指针而崩溃。

操作MRCARC
创建对象[[Object alloc] init][[Object alloc] init]
持有引用[object retain]自动
释放[object release]自动
自动释放[object autorelease]自动(不需要)
弱引用__weak不存在__weak(自动置nil)

ARC在Xcode 4.2和LLVM 3.0(2011年)中引入。编译器在编译阶段通过分析对象的生命周期自动插入retain/release。ARC不是垃圾回收——它是带有自动插入的静态分析。Objective-C ARC与Swift ARC兼容:两者在运行时级别使用相同的引用计数系统。

通过桥接头文件与Swift交互

在同一个项目中共用Objective-C和Swift——这是遗留项目的常见实践。Apple提供了桥接头文件——一个自动生成的文件,Swift通过它可以看到Objective-C类,Objective-C通过它可以看到继承自NSObject的Swift类。

objective-c
// ProjectName-Bridging-Header.h
// Swift自动看到这些头文件
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"

从Objective-C迁移到Swift——是一个逐步的过程。新文件用Swift编写,旧文件逐步重构。当向Objective-C项目添加第一个Swift文件时,桥接头文件会自动生成。对于反向可见性(ObjC → Swift),Xcode生成-Swift.h文件,其中包含标有@objc的Swift类的@interface。

swift
// 从Objective-C可见的Swift类
@objc class SwiftRouter: NSObject {
    @objc func navigateToProfile(userId: Int) {
        // 实现
    }
}

限制:Swift值类型(struct、enum)不能直接从Objective-C看到——需要用@objc包装在class中。Swift中的泛型从Objective-C访问受限。推荐的方法——用Swift编写新代码,仅在相关功能变化时重构现有的Objective-C代码。

Objective-C中的运行时和方法调配

Objective-C相对于Swift的主要优势——完全访问运行时。方法调配(Method swizzling)在运行时替换方法实现,允许在不继承的情况下覆盖系统方法。像Aspects和JRSwizzle这样的库利用此功能实现AOP(面向切面编程)——监控、分析和日志记录。

正向调用(Forward invocation) — 另一个运行时功能:如果对象不对选择器作出响应,系统会调用forwardInvocation:,允许将消息重定向到另一个对象。这是Objective-C中代理模式(NSProxy)的基础,用于延迟初始化和分布式对象。

Apple建议在新代码中尽量减少运行时技巧的使用,优先使用Swift的静态类型。然而,在遗留项目中,了解objc_msgSend、method_exchangeImplementations和objc_getAssociatedObject对于维护现有代码库是必要的。

属性和键值观察

Objective-C支持属性作为ivar上的语法糖,带有getter/setter。atomic/nonatomic、strong/weak/copy、readonly/readwrite和assign/retain修饰符决定了内存行为和线程安全性。键值观察(KVO)——内置于运行时的属性更改观察机制:任何对象都可以通过addObserver订阅另一个对象属性的更改。

常见问题

Objective-C中的消息语法是什么?

方法调用形式为[object selector:argument]。消息通过objc_msgSend传递,后者在运行时动态查找实现。选择器是方法的名称(@selector(methodName)),而不是函数指针。这允许方法调配和正向调用。

类别(Categories)和扩展(Extensions)有什么区别?

Category(@interface ClassName (Name))无需继承即可向任何类(包括系统类)添加方法。Extension(@interface ClassName ())在.m文件中声明,可以添加属性和ivar。Category不能添加ivar,Extension可以。

Objective-C中的块(Blocks)是什么?

Blocks——带有语法^(参数) { 体 }的匿名函数,从上下文捕获变量。类似于C++中的lambda和Swift中的闭包。在捕获self时需要__weak以防止保留循环。用于UIKit、GCD和Foundation。

ARC和MRC有什么区别?

MRC——手动引用计数:程序员调用retain、release、autorelease。ARC——自动:编译器基于静态分析插入retain/release。ARC不是垃圾回收——对象在计数器归零时立即释放。ARC支持__weak和__strong修饰符。

可以在一个项目中同时使用Objective-C和Swift吗?

可以,通过桥接头文件。Swift通过此头文件看到Objective-C,Objective-C通过-Swift.h看到Swift。Swift类必须继承自NSObject并标有@objc。Swift的struct和enum不能直接被Objective-C看到。

总结

  • Objective-C — C的严格超集,具有动态运行时和用于Cocoa/Cocoa Touch的消息语法
  • 消息传递 — 通过[object method]调用,通过objc_msgSend进行动态分发,可进行方法调配
  • 类别 — 无需继承即可向现有类添加方法,包括Apple系统类
  • — 带有闭包的匿名函数,需要__weak以防止保留循环
  • ARC vs MRC — 从手动retain/release到通过编译器自动引用计数的演进
  • 桥接头文件 — Swift和Objective-C在一个项目中协同工作的机制,用于逐步迁移
  • 遗留重要性 — App Store中约35%的应用包含需要支持的Objective-C代码

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读