从源码学习iOS开发:TZImagePickerController架构设计分析
引言:iOS图片选择器的痛点与解决方案
在iOS应用开发中,图片选择功能是许多应用的核心需求之一。然而,系统自带的UIImagePickerController在功能和用户体验上往往无法满足复杂场景的需求,例如多选图片、预览、裁剪、原图选择等。为了解决这些问题,开源社区涌现出了许多优秀的第三方图片选择器库,其中TZImagePickerController以其功能全面、性能优异和高度可定制性脱颖而出。
本文将深入剖析TZImagePickerController的架构设计,从核心组件、类关系、数据流程到设计模式,带您全面了解这个优秀的iOS图片选择器框架,为您的iOS开发学习和项目实践提供参考。
一、项目概述与核心功能
1.1 项目简介
TZImagePickerController是一个支持多选、选原图和视频的图片选择器,同时提供预览、裁剪功能,支持iOS 6+系统。它的设计目标是提供一个功能丰富、性能优良且易于集成的图片选择解决方案,替代系统自带的UIImagePickerController。
1.2 核心功能特性
TZImagePickerController提供了以下核心功能:
| 功能 | 描述 |
|---|---|
| 图片多选 | 支持同时选择多张图片,可自定义最大选择数量 |
| 原图选择 | 允许用户选择是否获取原图 |
| 视频选择 | 支持选择视频文件,并可预览 |
| 图片预览 | 提供图片预览功能,支持缩放、滑动切换 |
| 图片裁剪 | 支持对选中的图片进行裁剪 |
| GIF支持 | 支持GIF图片的预览和选择 |
| 自定义UI | 提供丰富的UI自定义选项,满足不同应用的设计需求 |
| 性能优化 | 通过缓存、异步加载等方式优化性能,确保流畅的用户体验 |
二、架构设计与核心组件
2.1 整体架构概览
TZImagePickerController采用了分层架构设计,主要分为以下几个层次:
- UI层:包含各种视图组件,如单元格、工具栏等
- 控制器层:负责页面跳转、用户交互和业务逻辑调度
- 业务逻辑层:处理图片加载、裁剪、缓存等核心业务逻辑
- 数据模型层:定义数据结构,管理相册和资源信息
- 系统相册框架:与iOS系统相册框架(Photos.framework)交互
2.2 核心组件分析
TZImagePickerController的核心组件主要包括以下几个关键类:
2.2.1 TZImagePickerController
TZImagePickerController是整个框架的入口类,继承自UINavigationController,负责协调各个组件,提供对外接口。
@interface TZImagePickerController : UINavigationController
// 初始化方法
- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate;
// 配置属性
@property (nonatomic, assign) NSInteger maxImagesCount; // 最大选择数量
@property (nonatomic, assign) BOOL allowPickingOriginalPhoto; // 是否允许选择原图
@property (nonatomic, assign) BOOL allowPickingVideo; // 是否允许选择视频
// ... 更多配置属性
// 回调Block
@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
// ... 更多回调Block
@end
2.2.2 TZImageManager
TZImageManager是图片管理的核心类,负责与系统相册框架交互,获取图片资源、处理图片加载、缓存等操作。
@interface TZImageManager : NSObject
+ (instancetype)manager; // 单例
// 获取相册
- (void)getAllAlbumsWithFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
// 获取图片
- (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
// 获取原图
- (PHImageRequestID)getOriginalPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
// ... 更多方法
@end
2.2.3 TZAssetModel与TZAlbumModel
TZAssetModel和TZAlbumModel是数据模型类,分别表示图片资源和相册信息。
typedef enum : NSUInteger {
TZAssetModelMediaTypePhoto = 0,
TZAssetModelMediaTypeLivePhoto,
TZAssetModelMediaTypePhotoGif,
TZAssetModelMediaTypeVideo,
TZAssetModelMediaTypeAudio
} TZAssetModelMediaType;
@interface TZAssetModel : NSObject
@property (nonatomic, strong) PHAsset *asset;
@property (nonatomic, assign) BOOL isSelected;
@property (nonatomic, assign) TZAssetModelMediaType type;
@property (nonatomic, copy) NSString *timeLength;
@end
@interface TZAlbumModel : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) PHFetchResult *result;
@property (nonatomic, strong) NSArray *models;
@property (nonatomic, assign) NSUInteger selectedCount;
@end
2.2.4 TZPhotoPickerController
TZPhotoPickerController是图片选择界面的控制器,负责展示相册中的图片列表,处理用户选择操作。
@interface TZPhotoPickerController : UIViewController
@property (nonatomic, strong) TZAlbumModel *model;
@end
2.2.5 TZPhotoPreviewController
TZPhotoPreviewController是图片预览控制器,负责展示选中图片的预览效果,支持缩放、滑动切换等操作。
@interface TZPhotoPreviewController : UIViewController
@property (nonatomic, strong) NSMutableArray *models;
@property (nonatomic, assign) NSInteger currentIndex;
@property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto);
@end
2.3 类关系图
以下是TZImagePickerController核心类之间的关系图:
三、数据流程分析
3.1 相册加载流程
相册加载是TZImagePickerController启动后的第一个关键流程,其主要步骤如下:
3.2 图片选择流程
用户选择图片的流程如下:
四、关键技术点与设计模式
4.1 单例模式
TZImageManager采用了单例模式,确保整个应用中只有一个图片管理器实例,统一管理图片加载、缓存等操作。
+ (instancetype)manager {
static TZImageManager *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[TZImageManager alloc] init];
});
return instance;
}
4.2 代理模式
TZImagePickerController通过代理模式(TZImagePickerControllerDelegate)将用户操作结果回调给应用层。
@protocol TZImagePickerControllerDelegate <NSObject>
@optional
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto;
- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker;
@end
4.3 观察者模式
TZImagePickerController使用KVO(Key-Value Observing)观察选中状态的变化,实时更新UI。
// 观察选中数量变化
[self addObserver:self forKeyPath:@"selectedCount" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"selectedCount"]) {
[self updateDoneButton];
}
}
4.4 懒加载与缓存
为了提高性能,TZImageManager实现了图片的懒加载和缓存机制。
- (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo, NSDictionary *info, BOOL isDegraded))completion {
// 计算目标尺寸
CGFloat targetSize = self.photoWidth;
// 配置请求选项
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeExact;
options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
options.synchronous = NO;
// 请求图片
return [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(targetSize, targetSize) contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
// 处理结果并回调
BOOL isDegraded = [info[PHImageResultIsDegradedKey] boolValue];
completion(result, info, isDegraded);
}];
}
五、性能优化策略
5.1 图片加载优化
TZImagePickerController在图片加载方面做了多项优化:
- 异步加载:图片加载操作在后台线程进行,避免阻塞UI主线程
- 分阶段加载:先加载缩略图,再加载高清图,提升用户体验
- 图片尺寸优化:根据显示需求加载合适尺寸的图片,避免内存浪费
- 取消无效请求:当Cell被复用或滚动出屏幕时,取消之前的图片请求
5.2 列表滚动优化
为了确保图片列表的流畅滚动,TZImagePickerController采取了以下措施:
- 重用机制:使用
UICollectionView的重用机制,减少视图创建销毁开销 - 预加载:实现图片的预加载,提前加载即将显示的图片
- 减少Cell复杂度:优化Cell的层级结构,减少绘制开销
- 异步计算:在后台线程计算Cell的布局和尺寸
5.3 内存管理优化
针对图片选择器容易出现的内存问题,TZImagePickerController做了以下优化:
- 图片缓存管理:实现合理的图片缓存策略,及时释放不再需要的图片内存
- 避免循环引用:在Block和代理中使用弱引用,避免内存泄漏
- 及时取消请求:在控制器销毁时,取消所有未完成的图片请求
六、可定制性设计
TZImagePickerController提供了丰富的自定义选项,允许开发者根据自己的需求定制UI和功能:
6.1 UI定制
// 自定义导航栏颜色
picker.naviBgColor = [UIColor redColor];
picker.naviTitleColor = [UIColor whiteColor];
// 自定义按钮图片
picker.takePictureImage = [UIImage imageNamed:@"custom_camera"];
picker.photoSelImage = [UIImage imageNamed:@"custom_selected"];
// 自定义单元格
picker.assetCellDidSetModelBlock = ^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
// 自定义Cell的外观
cell.backgroundColor = [UIColor lightGrayColor];
};
6.2 功能定制
// 配置选择功能
picker.allowPickingImage = YES;
picker.allowPickingVideo = NO;
picker.allowPickingGif = YES;
picker.maxImagesCount = 9;
// 配置裁剪功能
picker.allowCrop = YES;
picker.cropRect = CGRectMake(0, 0, 300, 300);
picker.needCircleCrop = YES;
// 自定义选择逻辑
picker.isAssetCanBeSelected = ^BOOL(PHAsset *asset) {
// 根据资产类型、大小等自定义选择逻辑
return asset.pixelWidth > 1000 && asset.pixelHeight > 1000;
};
七、学习与借鉴价值
7.1 架构设计启示
TZImagePickerController的架构设计给我们提供了以下启示:
- 单一职责原则:每个类只负责一个明确的功能,如
TZImageManager专注于图片管理,TZPhotoPickerController专注于图片展示 - 依赖注入:通过代理和Block将不同模块解耦,提高代码的可维护性和可测试性
- 面向接口编程:定义清晰的接口,如
TZImagePickerControllerDelegate,便于扩展和定制
7.2 代码质量与规范
TZImagePickerController的代码质量和规范值得学习:
- 命名规范:类名、方法名、属性名清晰明了,如
TZPhotoPreviewController、getOriginalPhotoWithAsset:completion: - 注释完善:关键方法和属性都有详细的注释,便于理解和使用
- 版本兼容:考虑了不同iOS版本的兼容性,如对iOS 6+的支持
- 错误处理:完善的错误处理机制,如权限请求失败、图片加载失败等情况的处理
7.3 实用技巧与最佳实践
从TZImagePickerController中,我们可以学到许多iOS开发的实用技巧和最佳实践:
- Photos框架使用:如何正确使用Photos框架获取相册数据、加载图片
- 性能优化:图片加载、列表滚动等场景的性能优化技巧
- UI定制:如何设计高度可定制的UI组件
- 内存管理:大型图片处理中的内存管理策略
八、总结与展望
TZImagePickerController作为一个优秀的iOS图片选择器框架,其架构设计清晰合理,代码质量高,功能丰富,性能优良。通过深入学习其源码,我们不仅可以掌握图片选择功能的实现方法,还可以学习到iOS应用架构设计的最佳实践。
随着iOS系统的不断更新和新特性的推出,TZImagePickerController也在不断演进。未来,我们可以期待它在以下方面的进一步优化:
- Swift重构:采用Swift语言重构,利用Swift的新特性提升性能和开发效率
- Combine框架集成:使用Combine框架优化异步操作和数据流管理
- SwiftUI支持:提供SwiftUI版本的接口,适应iOS开发的新趋势
- AI增强功能:集成AI功能,如智能相册分类、图片内容识别等
通过学习和借鉴TZImagePickerController的设计思想和实现方法,我们可以提升自己的iOS开发水平,设计出更优秀的iOS应用。
参考资料
- TZImagePickerController源码:https://gitcode.com/gh_mirrors/tz/TZImagePickerController
- Apple官方文档:Photos Framework
- iOS开发者文档:性能优化指南
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



