Objective-C — 一种具有动态消息分发的编程语言,由Brad Cox于20世纪80年代创建。Apple选择Objective-C作为NeXTSTEP的主要语言,随后用于iOS SDK。Programming With 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代码在Objective-C中都是正确的。对象层添加了类(@interface/@implementation)、类别、协议(@protocol)和动态类型(id)。文件扩展名为.m(实现)和.h(头文件)。
消息语法 — Objective-C与类C语言的主要区别。使用[object method:argument]代替object.method(argument)。每条消息通过objc_msgSend传递,该函数在运行时动态查找方法的实现。
// 具有命名参数的消息语法
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)声明。
// 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) — Objective-C中的匿名函数,捕获外部作用域中的变量。块语法:^(int x) { return x * 2; }。块在UIKit中用于回调处理程序,在Grand Central Dispatch中用于异步任务,在NSArray/NSDictionary集合中用于函数式操作。
// 块类型的声明
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]完全解决。
Objective-C经历了从MRC(手动引用计数)到ARC(自动引用计数)的历程。在MRC中,程序员手动调用retain(增加计数器)、release(减少)和autorelease(延迟释放)。这些调用中的错误会导致内存泄漏或因悬空指针而崩溃。
| 操作 | MRC | ARC |
|---|---|---|
| 创建对象 | [[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兼容:两者在运行时级别使用相同的引用计数系统。
在同一个项目中共用Objective-C和Swift——这是遗留项目的常见实践。Apple提供了桥接头文件——一个自动生成的文件,Swift通过它可以看到Objective-C类,Objective-C通过它可以看到继承自NSObject的Swift类。
// ProjectName-Bridging-Header.h
// Swift自动看到这些头文件
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"从Objective-C迁移到Swift——是一个逐步的过程。新文件用Swift编写,旧文件逐步重构。当向Objective-C项目添加第一个Swift文件时,桥接头文件会自动生成。对于反向可见性(ObjC → Swift),Xcode生成
// 从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相对于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订阅另一个对象属性的更改。
常见问题
方法调用形式为[object selector:argument]。消息通过objc_msgSend传递,后者在运行时动态查找实现。选择器是方法的名称(@selector(methodName)),而不是函数指针。这允许方法调配和正向调用。
Category(@interface ClassName (Name))无需继承即可向任何类(包括系统类)添加方法。Extension(@interface ClassName ())在.m文件中声明,可以添加属性和ivar。Category不能添加ivar,Extension可以。
Blocks——带有语法^(参数) { 体 }的匿名函数,从上下文捕获变量。类似于C++中的lambda和Swift中的闭包。在捕获self时需要__weak以防止保留循环。用于UIKit、GCD和Foundation。
MRC——手动引用计数:程序员调用retain、release、autorelease。ARC——自动:编译器基于静态分析插入retain/release。ARC不是垃圾回收——对象在计数器归零时立即释放。ARC支持__weak和__strong修饰符。
可以,通过桥接头文件。Swift通过此头文件看到Objective-C,Objective-C通过
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。