-
AppInfoModel.h
@interface AppInfoModel : NSObject
/// 标题名称
@property (nonatomic, strong) NSString *name;
/// 下载数量
@property (nonatomic, strong) NSString *download;
/// 图片地址
@property (nonatomic, strong) NSString *icon;
/// 从 Plist 加载 AppInfo
+ (NSArray *)loadPList;
@end
-
AppInfoModel.m
+ (NSArray *)loadPList {
NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]];
NSMutableArray *plist = [NSMutableArray arrayWithCapacity:array.count];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id model = [[self alloc] init];
[model setValuesForKeysWithDictionary:obj];
[plist addObject:model];
}];
return plist;
}
-
AppInfoCell.h
@interface AppInfoCell : UITableViewCell
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@property (nonatomic, weak) IBOutlet UILabel *downloadLabel;
@property (nonatomic, weak) IBOutlet UIImageView *iconImageView;
@end
-
NSString+BundlePath.h
/// 拼接缓存目录
- (NSString *)appendCachePath;
-
NSString+BundlePath.m
- (NSString *)appendCachePath {
NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
return [dir stringByAppendingPathComponent:self.lastPathComponent];
}
-
WebImageOperation.h
@interface WebImageOperation : NSOperation
/// 实例化 web 图像操作
+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *image))completion;
@end
-
WebImageOperation.m
/// 下载图片的 URL
@property (nonatomic, copy) NSString *urlStr;
/// 下载完成的回调
@property (nonatomic, copy) void (^completion) (UIImage *image);
+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *))completion {
WebImageOperation *imageOperation = [[self alloc] init];
imageOperation.urlStr= urlString;
imageOperation.completion = completion;
return imageOperation;
}
// 操作加入队列后会自动执行该方法
- (void)main {
@autoreleasepool {
if (self.isCancelled) return;
NSURL *url = [NSURL URLWithString:self.urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
if (self.isCancelled) return;
if (data != nil) {
[data writeToFile:self.urlStr.appendCachePath atomically:YES];
}
if (self.isCancelled) return;
if (self.completion && data != nil) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.completion([UIImage imageWithData:data]);
}];
}
}
}
-
WebImageManager.h
// 负责所有网络图像的下载操作以及缓存管理!
@interface WebImageManager : NSObject
/// 全局单例访问入口
+ (instancetype)sharedManager;
/// 下载网络图像
- (void)downloadImage:(NSString *)urlString completion:(void (^) (UIImage *image))completion;
/// 取消 urlString 对应的下载操作
- (void)cancelDownload:(NSString *)urlString;
@end
-
WebImageManager.m
/// 下载队列
@property (nonatomic, strong) NSOperationQueue *downloadQueue;
/// 下载操作缓冲池
@property (nonatomic, strong) NSMutableDictionary *downloadQueueCache;
/// 图片缓冲池
@property (nonatomic, strong) NSMutableDictionary *imageCache;
// 下载管理器
// 实例化下载管理器
+ (instancetype)sharedManager {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
// 下载操作
- (void)downloadImage:(NSString *)urlString completion:(void (^)(UIImage *))completion {
// 判断缓存中是否存在图像
if ([self checkCacheWithURLString:urlString]) {
if (completion != nil) {
// 直接回调,传递给调用方图像
completion(self.imageCache[urlString]);
}
return;
}
// 判断缓冲池中是否存在下载操作
if (self.downloadQueueCache[urlString] != nil) {
return;
}
WebImageOperation *downloadOperation = [WebImageOperation webImageOperationWithURLString:urlString
completion:^(UIImage *image) {
// 下载完成从操作缓冲池中移除操作
[self.downloadQueueCache removeObjectForKey:urlString];
// 下载完成添加到图片缓冲池中
[self.imageCache setObject:image forKey:urlString];
if (completion != nil) {
completion(image);
}
}];
// 将操作添加到缓冲池
[self.downloadQueueCache setObject:downloadOperation forKey:urlString];
// 将操作添加到队列
[self.downloadQueue addOperation:downloadOperation];
}
// 取消 urlString 对应的下载操作
- (void)cancelDownload:(NSString *)urlString {
// 从缓冲池拿到下载操作
WebImageOperation *downloadOperation = self.downloadQueueCache[urlString];
if (downloadOperation != nil) {
// 取消操作
[downloadOperation cancel];
// 从缓冲池中删除操作
[self.downloadQueueCache removeObjectForKey:urlString];
}
}
// 判断缓存中是否存在图像
- (BOOL)checkCacheWithURLString:(NSString *)urlString {
// 判断图片缓冲池中是否存在图像
if (self.imageCache[urlString] != nil) {
return YES;
}
UIImage *image = [UIImage imageWithContentsOfFile:[urlString appendCachePath]];
// 判断沙盒中是否存在图像
if (image != nil) {
[self.imageCache setObject:image forKey:urlString];
return YES;
}
return NO;
}
// 懒加载
- (NSOperationQueue *)downloadQueue {
if (_downloadQueue == nil) {
_downloadQueue = [[NSOperationQueue alloc] init];
}
return _downloadQueue;
}
- (NSMutableDictionary *)downloadQueueCache {
if (_downloadQueueCache == nil) {
_downloadQueueCache = [[NSMutableDictionary alloc] init];
}
return _downloadQueueCache;
}
- (NSMutableDictionary *)imageCache {
if (_imageCache == nil) {
_imageCache = [[NSMutableDictionary alloc] init];
}
return _imageCache;
}
-
UIImageView+WebImageView.h
@interface UIImageView (WebImageView)
/// 设置 Web 图像 URL,自动加载图像
- (void)setWebImageWithURL:(NSString *)urlString;
@end
-
UIImageView+WebImageView.m
#import <objc/runtime.h>
// 下载图片的 url
@property (nonatomic, copy) NSString *urlStr;
- (void)setWebImageWithURL:(NSString *)urlString {
// 屏蔽快速滑动重复添加下载
if ([self.urlStr isEqualToString:urlString]) {
return;
}
// 暂停之前的操作
if (self.urlStr != nil && ![self.urlStr isEqualToString:urlString]) {
[[WebImageManager sharedManager] cancelDownload:self.urlStr];
// 如果 ImageView 之前有图像-清空图像
self.image = nil;
}
// 记录新的 url
self.urlStr = urlString;
__weak typeof(self) weakSelf = self;
// 下载网络图片
[[WebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
weakSelf.image = image;
}];
}
// 向分类添加属性
// 运行时的关联对象,动态添加属性
const void *URLStrKey = "URLStrKey";
- (void)setUrlStr:(NSString *)urlString {
objc_setAssociatedObject(self, URLStrKey, urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)urlStr {
return objc_getAssociatedObject(self, URLStrKey);
}
-
ViewController.m
/// 表格数据源
@property (nonatomic, strong) NSArray *dataSourceArray;
// 懒加载
- (NSArray *)dataSourceArray {
if (_dataSourceArray == nil) {
_dataSourceArray = [AppInfoModel loadPList];
}
return _dataSourceArray;
}
// 表格视图数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSourceArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];
AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];
cell.nameLabel.text = dataModel.name;
cell.downloadLabel.text = dataModel.download;
[cell.iconImageView setWebImageWithURL:dataModel.icon];
return cell;
}