8.1 一个完整的 OC 程序
让我们把之前学到的东西拼装起来。如果不依赖 Xcode 的模板,一个纯粹的 OC 程序长什么样?
Greeter.h
#import <Foundation/Foundation.h>
// 定义协议
@protocol GreeterDelegate <NSObject>
- (void)greeterDidFinishGreeting:(NSString *)message;
@end
@interface Greeter : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, weak) id<GreeterDelegate> delegate;
- (instancetype)initWithName:(NSString *)name;
- (void)greet;
@end
Greeter.m
#import "Greeter.h"
@implementation Greeter
- (instancetype)initWithName:(NSString *)name {
self = [super init]; // 先初始化父类
if (self) {
_name = [name copy]; // 记住要 Copy 字符串
}
return self;
}
- (void)greet {
NSString *msg = [NSString stringWithFormat:@"Hello, %@!", self.name];
NSLog(@"%@", msg);
// 检查代理是否响应方法,然后发送消息
if ([self.delegate respondsToSelector:@selector(greeterDidFinishGreeting:)]) {
[self.delegate greeterDidFinishGreeting:msg];
}
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Greeter.h"
// 稍微作弊一下,直接在 main 里面实现协议
@interface MainRunner : NSObject <GreeterDelegate>
@end
@implementation MainRunner
- (void)greeterDidFinishGreeting:(NSString *)message {
NSLog(@"[Delegate Callback] Done: %@", message);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool { // 自动释放池,内存的保护伞
MainRunner *runner = [MainRunner new];
Greeter *g = [[Greeter alloc] initWithName:@"Objective-C"];
g.delegate = runner;
[g greet];
}
return 0;
}
8.2 解读
-
@autoreleasepool: 在 main 函数里,所有的 OC 对象通常都需要在这个池子里。当出了这个括号,临时的对象(autoreleased objects)就会被统一清理。 -
[super init]: OC 的初始化模式。先让爸爸初始化,爸爸同意了(返回非 nil),儿子再初始化。 -
respondsToSelector:: 这就是动态性的体现。我在运行时问你:“你会不会这招?”你会我才调,不会我就不调,防止崩。 -
Delegate 模式:
id<GreeterDelegate>。这里用id表示“随便什么对象”,只要它遵守GreeterDelegate协议。 这是 iOS 开发中最著名的设计模式。
8.3 Categories (分类)
OC 还有一个大杀器:Category。 你可以不通过继承,直接给现有的类(甚至是系统类 NSString)添加方法。
@interface NSString (Reverse)
- (NSString *)reversedString;
@end
这在 Swift 里叫 Extension。但 OC 的 Category 更加野蛮,甚至可以通过 Runtime 给分类添加属性(虽然有点绕)。
8.4 总结
这一部分我们了解了 OC 的骨架。 你可能会觉得有点繁琐。没错,OC 就是繁琐。 但这种繁琐中包含着一种确定性。所有的逻辑都赤裸裸地摆在桌面上,没有 Swift 那么多语法糖藏着掖着。 下一章,我们将进入深水区:Advanced & Runtime。