ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Objective-C入门指南:从环境搭建到实战项目开发

Objective-C入门指南:从环境搭建到实战项目开发 1. 项目概述为什么现在还要学Objective-C如果你刚接触iOS开发打开招聘网站或者技术社区满眼都是SwiftUI、Swift并发、Combine这些新潮词汇可能会产生一个疑问现在入行iOS还有必要去碰那个看起来有点“古老”的Objective-C吗直接学Swift不香吗作为一个从iOS 5时代一路走过来的老码农我的答案是非常有必要尤其是对于想深入理解iOS生态、进入中大型团队或维护存量项目的开发者而言Objective-C是你绕不开的一课。这不是情怀而是实实在在的工程现实。Swift固然是现代、安全、优雅但iOS的基石——那个庞大的Cocoa Touch框架其API设计、命名约定、内存管理模型乃至整个运行时Runtime机制都深深烙着Objective-C的印记。很多Swift中你觉得“理所当然”的语法糖或特性其底层实现逻辑在Objective-C时代就已经定型了。直接学Swift你是在“用”框架而理解了Objective-C你是在“懂”框架。这份理解能让你在遇到诡异崩溃比如经典的EXC_BAD_ACCESS、需要与C/C库桥接、或者阅读一些经典开源库如AFNetworking、SDWebImage的早期版本源码时不至于两眼一抹黑。更重要的是存量代码的海洋是巨大的。无数稳定运行了五年、十年的App其核心业务逻辑层很可能仍然是Objective-C写的。团队要招人维护、迭代、优化这些资产Objective-C技能就是硬通货。所以把Objective-C视为一门“底层语言”或“系统语言”来学习它会为你打开一扇理解iOS/macOS开发更深层次的大门让你从“API调用者”转变为“生态理解者”。2. 环境搭建与第一个Objective-C程序2.1 开发环境准备Xcode是唯一选择对于iOS/macOS开发Xcode是官方且几乎唯一的高效集成开发环境IDE。你不需要纠结于其他编辑器或工具链的组合至少在入门和绝大多数生产开发中Xcode提供了从编码、调试、界面设计到性能分析、打包上架的全套工具。获取与安装前往Mac App Store搜索“Xcode”并下载安装。文件很大通常超过10GB请确保网络通畅和磁盘空间充足。安装完成后第一次启动可能会提示安装额外的命令行工具和模拟器组件务必同意。关键组件认知编译器现代Xcode默认使用LLVM编译器前端对于Objective-C它调用的是clang。你不需要单独配置Xcode已集成。SDKiOS SDK包含了所有系统框架如UIKit、Foundation的头文件和库。创建项目时会自动关联。模拟器可以在Mac上运行和调试iOS App非常方便。但要注意模拟器运行的是x86_64架构的代码而真机是ARM架构某些底层行为或有差异。Interface Builder现已集成在Xcode中用于可视化设计用户界面虽然纯代码编写UI越来越流行但理解IB对维护老项目很重要。注意确保你的macOS系统版本与Xcode版本兼容。通常最新版的Xcode需要较新的macOS版本支持。如果为维护老项目需安装旧版Xcode可以从 Apple开发者网站 获取但需注意兼容性和安全问题。2.2 创建第一个Objective-C项目Hello, World!打开Xcode选择“Create a new Xcode project”。在模板选择界面选择“iOS” - “App”点击“Next”。填写项目信息Product Name:HelloObjectiveCInterface:Storyboard(这是传统且直观的方式我们先从这里开始)Language:Objective-C(关键选择)其他选项如组织标识符等可按需填写暂时不影响。选择项目存储位置点击“Create”。项目创建成功后你会看到Xcode自动生成了几个关键文件main.m: 程序的入口点。通常你不需要修改它。AppDelegate.h/AppDelegate.m: 应用委托处理应用生命周期事件启动、进入后台等。ViewController.h/ViewController.m: 一个视图控制器附带一个同名的.storyboard文件这是我们主要编写代码的地方。Main.storyboard: 可视化界面文件。让我们在ViewController.m的viewDidLoad方法里添加我们的第一行Objective-C代码- (void)viewDidLoad { [super viewDidLoad]; // 创建并配置一个标签 UILabel *helloLabel [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 40)]; helloLabel.text Hello, Objective-C World!; helloLabel.textAlignment NSTextAlignmentCenter; helloLabel.backgroundColor [UIColor lightGrayColor]; // 将标签添加到当前视图控制器的根视图上 [self.view addSubview:helloLabel]; // 在控制台打印日志 NSLog(视图加载完毕标签已添加。); }代码解析与第一个“坑”[[UILabel alloc] initWithFrame:...]: 这是Objective-C最经典的消息发送语法。[对象 方法]。这里向UILabel类发送了alloc消息类方法分配内存然后向分配好的实例发送initWithFrame:消息实例方法进行初始化。这种嵌套调用非常常见。*helloLabel: Objective-C中的对象变量本质上都是指向对象内存地址的指针所以声明时需要用*。NSLog: 相当于Swift的printC的printf是调试输出的好朋友。内存管理初窥我们用了alloc按照“谁创建谁释放”的老规则MRC后续需要手动release。但在我们创建项目时Xcode默认启用了ARC自动引用计数编译器会自动在合适的地方插入retain,release,autorelease调用所以这里我们不需要手动管理。这是Objective-C现代编程中最重要的进步之一但理解其原理至关重要后文会详述。点击Xcode左上角的运行按钮▶️选择一款iPhone模拟器你的第一个Objective-C应用就应该运行起来屏幕上显示着灰色的标签。3. Objective-C核心语法精要3.1 面向对象基石类、对象与消息传递Objective-C是一门在C语言基础上添加了Smalltalk风格消息机制的面向对象语言。它的面向对象模型与C/Java有显著不同。1. 类的声明.h文件与实现.m文件这是Objective-C最经典的文件组织方式强调接口与实现的分离。ViewController.h(接口/头文件):#import UIKit/UIKit.h // 导入系统框架头文件 // interface 声明类继承自 UIViewController interface ViewController : UIViewController // 属性声明编译器会自动生成getter、setter和实例变量(_propertyName) property (nonatomic, strong) NSString *userName; property (nonatomic, assign) NSInteger age; // 方法声明实例方法以 ‘-’ 开头类方法以 ‘’ 开头 - (void)updateUserInfoWithName:(NSString *)name age:(NSInteger)age; (NSString *)classDescription; end#import确保头文件只被包含一次避免重复定义。property声明属性。括号内的nonatomic非原子性能好和strong强引用是属性特性是内存管理和线程安全的关键。-/分别代表实例方法和类方法。ViewController.m(实现文件):#import ViewController.h // 导入自己的头文件 // implementation 实现类 implementation ViewController // 可选synthesize 指令现代ARC下通常省略编译器自动合成 // synthesize userName _userName; // 实现声明的方法 - (void)updateUserInfoWithName:(NSString *)name age:(NSInteger)age { self.userName name; // 使用self.访问属性会触发setter _age age; // 直接访问实例变量不会触发KVO等 NSLog(用户信息更新为%, %ld岁, name, (long)age); } (NSString *)classDescription { return 这是一个视图控制器类。; } // 生命周期方法当视图加载完成时调用 - (void)viewDidLoad { [super viewDidLoad]; // 必须调用父类实现 [self updateUserInfoWithName:小明 age:25]; NSString *desc [ViewController classDescription]; // 调用类方法 NSLog(%, desc); } end2. 消息传递Message Passing:这是Objective-C的灵魂。[receiver message]不是“调用函数”而是“向对象发送消息”。运行时系统Runtime会查找receiver能否响应message这个过程是动态的。这带来了极大的灵活性也是很多高级特性如方法交换、动态解析的基础。// 发送消息 UILabel *label [[UILabel alloc] init]; [label setText:动态文本]; // 消息发送 // 等价于点语法是setter/getter的语法糖本质还是消息发送 label.text 动态文本;3.2 内存管理从MRC到ARC的演进与理解这是Objective-C初学者最大的“拦路虎”也是必须攻克的核心。MRC手动引用计数时代开发者需要手动平衡retain引用计数1,release引用计数-1,autorelease延迟释放。// MRC 示例现在很少需要手写 NSObject *obj1 [[NSObject alloc] init]; // retainCount 1 [obj1 retain]; // retainCount 2 [obj1 release]; // retainCount 1 [obj1 release]; // retainCount 0对象被立即销毁黄金法则alloc/new/copy/mutableCopy创建的对象你拥有所有权需负责release。通过其他方法如类工厂方法获取的对象你不拥有所有权通常已是autorelease的。ARC自动引用计数时代编译器在编译期自动在合适位置插入内存管理代码。开发者只需关注对象的引用关系。属性特性Property Attributesstrong强引用持有对象目标对象引用计数1。用于对象属性是默认值对于对象类型。weak弱引用不持有对象引用计数不变。当对象被销毁时该指针自动置为nil。完美用于解决循环引用如delegate、IBOutlet。copy建立一份对象的拷贝需对象实现NSCopying协议。常用于NSString、NSArray等可变/不可变类防止外部修改影响内部值。assign简单赋值用于基本数据类型NSInteger,CGFloat,BOOL等。变量修饰符__strong默认,__weak,__unsafe_unretained类似assign但对象销毁后指针不置空危险。循环引用与解决// 典型循环引用两个对象互相强引用导致都无法释放。 interface ClassA : NSObject property (strong, nonatomic) ClassB *b; end interface ClassB : NSObject property (strong, nonatomic) ClassA *a; // 强引用导致循环 end // 解决方案将其中一端改为弱引用 interface ClassB : NSObject property (weak, nonatomic) ClassA *a; // 改为weak打破循环 end实操心得在iOS开发中delegate属性几乎总是应该声明为weakIBOutlet属性Xcode自动生成的也是weak因为视图本身已被其父视图强引用。block内部捕获self时也容易引起循环引用需要使用__weak修饰符。3.3 核心框架Foundation与UIKit初探Foundation提供OC的基础类运行于iOS和macOS。NSString/NSMutableString: 字符串。永远多用copy特性。NSArray/NSMutableArray: 数组。有序集合只能存储对象。NSDictionary/NSMutableDictionary: 字典。键值对集合。NSNumber,NSDate,NSData等。集合遍历推荐使用快速枚举(for...in)或Block枚举(enumerateObjectsUsingBlock:)性能和安全性好于传统for循环。UIKit构建iOS应用用户界面的框架。UIView: 所有视图的基类。管理矩形区域内的内容绘制和触摸事件。UIViewController: 视图控制器管理视图层次结构响应用户交互是MVC模式中的“C”。UILabel,UIButton,UITextField等具体的控件。响应者链Responder Chain触摸事件、运动事件等传递的机制。理解它对于处理复杂交互至关重要。4. 第一个功能完整的Objective-C应用简易待办清单让我们构建一个简单的待办事项列表应用涵盖数据模型、列表展示、用户交互和持久化。4.1 数据模型与单例数据管理器创建数据模型TodoItem:新建TodoItem.h/m文件。// TodoItem.h #import Foundation/Foundation.h interface TodoItem : NSObject NSCoding // 实现NSCoding以支持归档 property (nonatomic, copy) NSString *title; property (nonatomic, assign) BOOL completed; property (nonatomic, strong) NSDate *createDate; - (instancetype)initWithTitle:(NSString *)title; end // TodoItem.m #import TodoItem.h implementation TodoItem - (instancetype)initWithTitle:(NSString *)title { self [super init]; if (self) { _title [title copy]; // 使用copy保证安全 _completed NO; _createDate [NSDate date]; } return self; } // NSCoding协议实现用于归档/解档 - (instancetype)initWithCoder:(NSCoder *)coder { self [super init]; if (self) { _title [coder decodeObjectForKey:title]; _completed [coder decodeBoolForKey:completed]; _createDate [coder decodeObjectForKey:createDate]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.title forKey:title]; [coder encodeBool:self.completed forKey:completed]; [coder encodeObject:self.createDate forKey:createDate]; } end创建数据管理器TodoDataManager单例模式:单例确保全局只有一个数据源便于管理。// TodoDataManager.h #import Foundation/Foundation.h class TodoItem; interface TodoDataManager : NSObject (instancetype)sharedManager; property (nonatomic, strong, readonly) NSMutableArrayTodoItem * *allItems; - (void)addTodoItem:(TodoItem *)item; - (void)removeTodoItemAtIndex:(NSUInteger)index; - (void)toggleCompletionForItemAtIndex:(NSUInteger)index; - (void)saveData; // 保存到文件 - (void)loadData; // 从文件加载 end // TodoDataManager.m #import TodoDataManager.h #import TodoItem.h implementation TodoDataManager { NSMutableArrayTodoItem * *_allItems; } (instancetype)sharedManager { static TodoDataManager *sharedInstance nil; static dispatch_once_t onceToken; dispatch_once(onceToken, ^{ sharedInstance [[self alloc] init]; }); return sharedInstance; } - (instancetype)init { self [super init]; if (self) { _allItems [NSMutableArray array]; [self loadData]; } return self; } - (NSMutableArrayTodoItem * *)allItems { return _allItems; } - (void)addTodoItem:(TodoItem *)item { [_allItems insertObject:item atIndex:0]; // 新事项加在前面 [self saveData]; } - (void)removeTodoItemAtIndex:(NSUInteger)index { if (index _allItems.count) { [_allItems removeObjectAtIndex:index]; [self saveData]; } } - (void)toggleCompletionForItemAtIndex:(NSUInteger)index { if (index _allItems.count) { TodoItem *item _allItems[index]; item.completed !item.completed; [self saveData]; } } - (NSString *)dataFilePath { NSArray *paths NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory [paths firstObject]; return [documentsDirectory stringByAppendingPathComponent:todoitems.archive]; } - (void)saveData { NSString *path [self dataFilePath]; // 使用NSKeyedArchiver进行归档 BOOL success [NSKeyedArchiver archiveRootObject:_allItems toFile:path]; NSLog(数据保存%: %, success ? 成功 : 失败, path); } - (void)loadData { NSString *path [self dataFilePath]; NSArray *loadedItems [NSKeyedUnarchiver unarchiveObjectWithFile:path]; if ([loadedItems isKindOfClass:[NSArray class]]) { _allItems [loadedItems mutableCopy]; } NSLog(加载了 %lu 条待办事项, (unsigned long)_allItems.count); } end4.2 使用UITableView展示列表界面布局:打开Main.storyboard从对象库拖拽一个Table View到ViewController的视图上并使其铺满整个安全区域。选中这个Table View在右侧属性检查器中将Prototype Cells的数量设为1。点击原型Cell将其Style改为BasicIdentifier设为TodoCell。再拖拽一个Text Field和一个Button到表格上方作为添加新待办的输入区。连接IBOutlet与IBAction:打开辅助编辑器Assistant Editor确保ViewController.m和storyboard并列显示。Control Drag从Table View拖到ViewController.m的interface扩展区域创建一个名为tableView的Outlet。同样为Text Field创建名为inputTextField的Outlet。Control Drag从Button拖到ViewController.m的实现区域创建一个Action命名为addButtonTapped:。实现UITableViewDataSource和UITableViewDelegate:在ViewController.h中声明遵守协议UITableViewDataSource, UITableViewDelegate。在ViewController.m的viewDidLoad中设置代理和数据源self.tableView.dataSource self; self.tableView.delegate self;实现必须的协议方法#pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [TodoDataManager sharedManager].allItems.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 重用Cell这是保证列表流畅的关键 UITableViewCell *cell [tableView dequeueReusableCellWithIdentifier:TodoCell forIndexPath:indexPath]; TodoItem *item [TodoDataManager sharedManager].allItems[indexPath.row]; cell.textLabel.text item.title; // 根据完成状态设置勾选样式 cell.accessoryType item.completed ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; // 已完成的事项文字变灰 cell.textLabel.textColor item.completed ? [UIColor lightGrayColor] : [UIColor blackColor]; return cell; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; // 取消选中状态 // 切换完成状态 [[TodoDataManager sharedManager] toggleCompletionForItemAtIndex:indexPath.row]; // 刷新当前行 [tableView reloadRowsAtIndexPaths:[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } // 左滑删除 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle UITableViewCellEditingStyleDelete) { [[TodoDataManager sharedManager] removeTodoItemAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } }实现添加功能:- (IBAction)addButtonTapped:(UIButton *)sender { NSString *text self.inputTextField.text; if (text.length 0) { TodoItem *newItem [[TodoItem alloc] initWithTitle:text]; [[TodoDataManager sharedManager] addTodoItem:newItem]; // 清空输入框 self.inputTextField.text nil; // 刷新表格在首行插入动画更佳 NSIndexPath *newIndexPath [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView insertRowsAtIndexPaths:[newIndexPath] withRowAnimation:UITableViewRowAnimationTop]; // 滚动到顶部 [self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; } else { // 简单提示 UIAlertController *alert [UIAlertController alertControllerWithTitle:提示 message:请输入待办内容 preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:确定 style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } // 收起键盘 [self.inputTextField resignFirstResponder]; }运行应用你现在应该有一个可以添加、完成点击、删除左滑并持久化保存的简易待办清单了。这个项目虽然简单但涵盖了MVC架构、数据持久化、表格视图、用户交互等核心模式。5. 进阶概念与常见问题排查5.1 深入理解Category、Extension与ProtocolCategory分类在不修改原始类的情况下为已有类添加方法。不能添加属性关联对象除外或实例变量。常用于功能模块化。// NSStringUtils.h interface NSString (Utils) - (BOOL)isValidEmail; end // NSStringUtils.m implementation NSString (Utils) - (BOOL)isValidEmail { // 简单的邮箱格式验证正则 NSString *emailRegex [A-Z0-9a-z._%-][A-Za-z0-9.-]\\.[A-Za-z]{2,64}; NSPredicate *predicate [NSPredicate predicateWithFormat:SELF MATCHES %, emailRegex]; return [predicate evaluateWithObject:self]; } end // 使用 [testexample.com isValidEmail];Extension类扩展/匿名Category写在.m文件里用于声明私有属性、方法或遵循的私有协议。它扩展的方法必须在主implementation中实现。// ViewController.m interface ViewController () // 类扩展 property (nonatomic, strong) NSMutableArray *privateData; - (void)privateHelperMethod; end implementation ViewController // 必须实现privateHelperMethod - (void)privateHelperMethod { /* ... */ } endProtocol协议定义一组方法声明由类来遵循实现。类似于其他语言的接口。optional声明可选实现的方法。protocol DataFetcherDelegate NSObject required - (void)dataFetcher:(id)fetcher didReceiveData:(NSData *)data; optional - (void)dataFetcherDidFail:(id)fetcher withError:(NSError *)error; end interface MyDataFetcher : NSObject property (nonatomic, weak) idDataFetcherDelegate delegate; end5.2 调试与常见崩溃解析Objective-C的崩溃信息有时比较晦涩掌握常见类型能快速定位问题。EXC_BAD_ACCESS(SIGSEGV/SIGBUS)原因访问了已释放野指针或无效的内存地址。这是ARC时代之前最常见也最令人头疼的崩溃。排查启用僵尸对象Zombie Objects在Xcode的Scheme设置中Diagnostics下勾选Enable Zombie Objects。运行后当访问已释放对象时会给出更明确的错误信息指出访问的是什么对象。检查weak引用是否在对象销毁后意外被访问。检查C语言层面的指针操作如C数组越界。NSInvalidArgumentException原因向方法传递了非法参数最常见的是向集合类NSArray,NSDictionary插入nil。示例[array addObject:nil];或{key: nilObj};解决在插入前判断对象是否为nil。使用字面量语法创建字典/数组时内部元素不能为nil。unrecognized selector sent to instance 0x...原因对象无法响应发送给它的消息方法不存在。排查检查对象类型是否正确是否是你期望的类实例。检查方法名是否拼写错误。检查该对象是否已被释放又回到野指针问题。工具在异常断点处使用po [object class]打印对象真实类。UITableView / UICollectionView 数据源不一致崩溃原因在numberOfRowsInSection:返回的数量与cellForRowAtIndexPath:或commitEditingStyle:等方法中操作的数据源如数组数量不一致特别是在并发修改时。黄金法则先更新数据源再更新UI。// 错误示范先删UI再删数据 [self.tableView deleteRowsAtIndexPaths:[indexPath] withRowAnimation:...]; [self.dataArray removeObjectAtIndex:indexPath.row]; // 崩溃 // 正确示范先删数据再删UI [self.dataArray removeObjectAtIndex:indexPath.row]; [self.tableView deleteRowsAtIndexPaths:[indexPath] withRowAnimation:...];5.3 与Swift混编及桥接在现代项目中你很可能需要在Objective-C中调用Swift代码反之亦然。在Objective-C项目中调用Swift创建一个Swift文件Xcode会提示创建桥接头文件项目名-Bridging-Header.h点确认。在Swift文件中定义的类需要继承自NSObject并且使用objc或objcMembers公开。在Objective-C文件中导入自动生成的头文件#import 项目名-Swift.hXcode自动完成不可见但可用。// MySwiftClass.swift import UIKit objcMembers // 公开所有成员给OC class MySwiftClass: NSObject { var name: String init(name: String) { self.name name } func greet() { print(Hello from Swift, \(name)!) } }// ViewController.m #import YourProject-Swift.h // 导入Swift生成的头文件 MySwiftClass *swiftObj [[MySwiftClass alloc] initWithName:OC]; [swiftObj greet];在Swift项目中调用Objective-C将Objective-C的.h和.m文件拖入项目。在桥接头文件项目名-Bridging-Header.h中#import你需要暴露给Swift的Objective-C头文件。在Swift中即可直接使用这些Objective-C类。// OldObjectiveCClass.h interface OldObjectiveCClass : NSObject - (void)oldMethod; end// Bridging-Header.h #import OldObjectiveCClass.h// SomeSwiftFile.swift let oldObj OldObjectiveCClass() oldObj.oldMethod()实操心得混编时命名需注意Swift会尝试将Objective-C的命名转换为更“Swift化”的样式如将initWithName:转换为init(name:)。仔细阅读Xcode的自动完成提示。另外一些Swift特有的类型如元组、泛型、枚举的关联值无法直接暴露给Objective-C。6. 从入门到进阶的学习路径与资源掌握了上述基础后你已能读懂和编写大部分Objective-C代码。但要成为高手还需要深入以下领域深入Runtime理解objc_msgSend、方法交换Method Swizzling、关联对象Associated Objects、动态方法解析等。这是理解KVO、KVC、AOP等高级特性的基础。推荐阅读Apple的 Runtime Programming Guide 。内存管理深潜即使有ARC也要理解autoreleasepool的工作原理、循环引用的各种场景特别是Block和NSTimer、__bridge系列转换与Core Foundation交互等。多线程与GCDGrand Central Dispatch是iOS多线程编程的核心。精通dispatch_queue、dispatch_group、dispatch_semaphore理解同步/异步、串行/并行的区别以及线程安全的数据访问。网络与数据持久化超越NSUserDefaults和归档学习NSURLSession进行网络请求掌握Core Data或SQLite通过FMDB等封装库进行复杂数据管理了解Keychain安全存储。性能优化使用Instruments工具分析CPU、内存、电量、网络。掌握离屏渲染、图层混合、单元格复用、图片解码等优化技巧。阅读优秀源码AFNetworking、SDWebImage、YYKit等经典库的早期Objective-C版本是绝佳的学习材料你能看到大量严谨的内存管理、线程安全和优雅的设计模式实践。学习Objective-C的过程也是深入理解Cocoa框架设计哲学的过程。这份理解会让你在使用Swift时更加得心应手知其然更知其所以然。当你再看到Swift中objc、dynamic这样的修饰符或者处理与C库的交互时你会感谢当初踏实地学好了Objective-C。它或许不再是未来的主角但无疑是构建你坚实iOS开发知识体系中不可或缺、承前启后的关键一环。
返回列表