ios基础篇(十五)—— SDWebImage

el/2023/6/4 14:54:38

一、SDWebImage介绍

  • 什么是SDWebImage
    • iOS中著名的牛逼的网络图片处理框架
    • 包含的功能:图片下载、图片缓存、下载进度监听、gif处理等等
    • 用法极其简单,功能十分强大,大大提高了网络图片的处理效率
    • 国内超过90%的iOS项目都有它的影子
  • 项目地址
    • https://github.com/rs/SDWebImage
  • 下载SDWebImage
  • 查看文档,SDWebImage的基本使用
    • 导入UIImageView+WebCache头文件
    • 下载图片,并显示在imageView中
[self.imageView sd_setImageWithURL:url];

异步下载网络图片 使用SDWebImage

#import "ViewController.h"
#import "HMAppInfo.h"
#import "HMAppInfoCell.h"
#import "NSString+Sandbox.h"
@interface ViewController ()
@property (nonatomic, strong) NSArray *appInfos;
@end
@implementation ViewController
//懒加载
- (NSArray *)appInfos {if (_appInfos == nil) {_appInfos = [HMAppInfo appInfos];}return _appInfos;
}
//2 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return self.appInfos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {//1 创建可重用的cellstatic NSString *reuseId = @"appInfo";HMAppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId];//2 获取数据,给cell内部子控件赋值HMAppInfo *appInfo = self.appInfos[indexPath.row];    cell.appInfo = appInfo;//3 返回cellreturn cell;
}
@end

HMAppInfoCell.m    图片重命名是防止不同服务器过来的图片 重复  是通过md5值计算过的

#import "HMAppInfoCell.h"
#import "HMAppInfo.h"
#import "UIImageView+WebCache.h"
@interface HMAppInfoCell ()
@property (weak, nonatomic) IBOutlet UILabel *nameView;
@property (weak, nonatomic) IBOutlet UILabel *downloadView;
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@end@implementation HMAppInfoCell- (void)setAppInfo:(HMAppInfo *)appInfo {_appInfo = appInfo;self.nameView.text = appInfo.name;self.downloadView.text = appInfo.download;    [self.iconView sd_setImageWithURL:[NSURL URLWithString:appInfo.icon]];}
@end

二、自定义Operation

  • 自定义Operation的目的:封装下载图片的操作
  • 自定义Operation,模拟下载图片
    • 创建HMDownloaderOperation类,继承自NSOperation
    • 重写自定义Operation的main方法
      • 重写- (void)main方法,在里面实现想执行的任务
      • 自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池
      • 经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
    • 在controller中调用start方法,或者添加到队列。main方法会被调用

自动释放池 1.循环内部创建了大量的临时对象  2.子线程无法访问主线程的自动释放池

传参和其他

  • 自定义Operation传参
//要下载的图片的地址
@property (nonatomic, copy) NSString *urlString;//回调
@property (nonatomic, copy) void (^finishedBlock)(UIImage *img);

断言的使用

 NSAssert(self.finishedBlock != nil, @"finishedBlock 不能为nil”);

 自定义Operation取消操作

 if (self.isCancelled) {return;}

HMDownloaderOperation.h

#import <UIKit/UIKit.h>
//自定义操作
//1 创建一个类继承自NSOperation
//2 重写main方法,自动释放池
//3 定义属性接收参数 , 类方法快速初始化自定义操作
//4 取消操作(取消正在执行的操作)
//5 断言NSAssert
@interface HMDownloaderOperation : NSOperation
//要下载图片的地址
@property (nonatomic, copy) NSString *urlString;
//执行完成后,回调的block
@property (nonatomic, copy) void (^finishedBlock)(UIImage *img);
+ (instancetype)downloaderOperationWithURLString:(NSString *)urlString finishedBlock:(void(^)(UIImage *img))finishedBlock;
@end

HMDownloaderOperation.m

#import "HMDownloaderOperation.h"
@implementation HMDownloaderOperation
+ (instancetype)downloaderOperationWithURLString:(NSString *)urlString finishedBlock:(void (^)(UIImage *))finishedBlock {HMDownloaderOperation *op = [[HMDownloaderOperation alloc] init];op.urlString = urlString;op.finishedBlock = finishedBlock;return op;
}
- (void)main {@autoreleasepool {//断言NSAssert(self.finishedBlock != nil, @"finishedBlock 不能为nil");        //模拟网络延时[NSThread sleepForTimeInterval:2.0];//判断是否被取消  取消正在执行的操作if (self.isCancelled) {return;}NSLog(@"下载图片 %@ %@",self.urlString,[NSThread currentThread]);//UIImage    //假设图片下载完成//回到主线程更新UI
//        if (self.finishedBlock) {[[NSOperationQueue mainQueue] addOperationWithBlock:^{self.finishedBlock(self.urlString);}];
//        }}
}
@end

ViewController.m

#import "ViewController.h"
#import "HMDownloaderOperation.h"
@interface ViewController ()
//全局队列
@property (nonatomic, strong) NSOperationQueue *queue;
@end
@implementation ViewController
//懒加载
- (NSOperationQueue *)queue {if (_queue == nil) {_queue = [[NSOperationQueue alloc] init];_queue.maxConcurrentOperationCount = 2;}return _queue;
}
- (void)viewDidLoad {[super viewDidLoad];for (int i = 0; i<20; i++) {HMDownloaderOperation *op = [HMDownloaderOperation downloaderOperationWithURLString:@"abc.jpg" finishedBlock:^(UIImage *img) {//图片下载完成更新UINSLog(@"更新UI %d  %@",i,[NSThread currentThread]);}];        [self.queue addOperation:op];        }//演示断言
//    HMDownloaderOperation *op = [HMDownloaderOperation downloaderOperationWithURLString:@"abc.jpg" finishedBlock:nil];
//    [self.queue addOperation:op];  
//    //自定义操作
//    HMDownloaderOperation *op = [[HMDownloaderOperation alloc] init];
//    op.urlString = @"xxx.jpg";
//    //无法传递参数[op setCompletionBlock:^{     NSLog(@"给控件赋值");}];
//    [op setFinishedBlock:^(UIImage *img) {
//        NSLog(@"给控件赋值 %@",img);
//    }];   
//    [self.queue addOperation:op];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//设置所有操作的canceled属性为yes[self.queue cancelAllOperations];NSLog(@"取消");
}

下载网络图片

//断言的使用NSAssert(self.finishedBlock != nil, @"finishedBlock 不能为nil");        //下载网络图片NSURL *url = [NSURL URLWithString:self.urlString];NSData *data = [NSData dataWithContentsOfURL:url];[NSThread sleepForTimeInterval:1.0];//保存到沙盒if (data) {[data writeToFile:[self.urlString appendCachePath] atomically:YES];}//取消操作if (self.isCancelled) {return;}//主线程更新UI[[NSOperationQueue mainQueue] addOperationWithBlock:^{UIImage *img = [UIImage imageWithData:data];self.finishedBlock(img);}];

测试下载图片

controller中测试//获取随机的数字int random = arc4random_uniform((u_int32_t)self.appInfos.count);//随机获取模型HMAppInfo *appInfo = self.appInfos[random];//判断当前要下载的图片,是不是刚刚下载过的if (![appInfo.icon isEqualToString:self.currentURLString]) {//取消操作[self.operationCache[self.currentURLString] cancel];}    //记录当前显示的图片地址self.currentURLString = appInfo.icon;    //下载并设置图片HMDownloaderOperation *op = [HMDownloaderOperation downloaderOperationWithURLString:appInfo.icon finishedBlock:^(UIImage *img) {self.imageview.image = img;//移除下载操作[self.operationCache removeObjectForKey:appInfo.icon];}];[self.queue addOperation:op];//缓存当前下载操作[self.operationCache setObject:op forKey:appInfo.icon];

仿SDWebImage

下载操作管理类

  • 作用
    • 管理全局的下载操作
    • 管理全局的图片缓存
  • 单例方法
+ (instancetype)sharedManager {static id instance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [[self alloc] init];});return instance;
}
  • 属性和懒加载
@property (nonatomic, strong) NSOperationQueue *queue;
//操作缓存池
@property (nonatomic, strong) NSMutableDictionary *operationCache;
//懒加载
- (NSOperationQueue *)queue {if (_queue == nil) {_queue = [NSOperationQueue new];}return _queue;
}
- (NSMutableDictionary *)operationCache {if (_operationCache == nil) {_operationCache = [NSMutableDictionary dictionary];}return _operationCache;
}
  • 下载的方法
- (void)downloaderOperationWithURLString:(NSString *)urlString finishedBlock:(void (^)(UIImage *))finishedBlock {//断言NSAssert(finishedBlock != nil, @"finishedBlock不能为nil");//如果下载操作已经存在,退出if (self.operationCache[urlString]) {return;}//下载并设置图片HMDownloaderOperation *op = [HMDownloaderOperation downloaderOperationWithURLString:urlString finishedBlock:^(UIImage *img) {//移除下载操作[self.operationCache removeObjectForKey:urlString];//回调finishedBlock(img);}];[self.queue addOperation:op];//缓存当前下载操作[self.operationCache setObject:op forKey:urlString];
}
  • 取消的方法
- (void)cancelOperation:(NSString *)urlString {if (urlString == nil) {return;}//取消操作[self.operationCache[urlString] cancel];//从缓存池中移除[self.operationCache removeObjectForKey:urlString];
}
  • 缓存管理
//图片缓存
@property (nonatomic, strong) NSMutableDictionary *imageCache;
//下载图片之前,先检查图片缓存if ([self checkImageCache:urlString]) {finishedBlock(self.imageCache[urlString]);return;}
- (BOOL)checkImageCache:(NSString *)urlString {//1 检查内存缓存if (self.imageCache[urlString]) {NSLog(@"内存缓存");return YES;}//2 检查沙盒缓存UIImage *img = [UIImage imageWithContentsOfFile:[urlString appendCachePath]];if (img) {NSLog(@"沙盒缓存");//保存到内存缓存[self.imageCache setObject:img forKey:urlString];return YES;}return NO;
}

UIImageView的分类

  • 模拟SDWebImage一行代码下载图片,创建UIImageView的分类
//记录当前显示的图片地址
@property (nonatomic, copy) NSString *currentURLString;
//设置图片的地址,下载图片
- (void)setImageUrlString:(NSString *)urlString {//判断当前要下载的图片,是不是刚刚下载过的if (![urlString isEqualToString:self.currentURLString]) {//取消操作[[HMDownloaderOperationManager sharedManager] cancelOperation:self.currentURLString];}//记录当前显示的图片地址self.currentURLString = urlString;    //下载图片[[HMDownloaderOperationManager sharedManager] downloaderOperationWithURLString:urlString finishedBlock:^(UIImage *img) {self.image = img;}];
}

问题

  • 下载图片,崩溃
  • 分类中不能直接添加输入,如果添加属性需要重写setter和getter方法。

关联对象

#import <objc/runtime.h>
#define HMMYKEY "str"
//关联对象,存储一个值objc_setAssociatedObject(self, HMMYKEY, currentURLString, OBJC_ASSOCIATION_COPY_NONATOMIC);
//关联对象,取出值return objc_getAssociatedObject(self, HMMYKEY);

第三方框架

  • 什么是第三方框架
    • 非官方制作的一些解决某一类的问题的框架(类库)
    • 使用人数较多的框架,得到了充分的测试,bug几乎没有
    • 一般开源
    • 使用简单,方便
  • 一般的使用步骤
    • 看demo
    • 看文档
    • 通过文档试用,编译
    • 实现自己项目中对应的功能
    • 有空看源代码

NSCache

1. NSCache苹果提供的一套缓存机制

a. 和NSMutableDictionary使用起来相似

b. 线程安全,Mutable开发的类一般都是线程不安全的

c. 当内存不足时会自动释放内存(所以从缓存中取数据的时候总要判断是否为空)

d. 指定缓存的限额,当缓存超出限额自动释放内存

i. 缓存限额:

 1) 缓存数量

 @property NSUInteger countLimit;

2) 缓存成本

@property NSUInteger totalCostLimit;

2. 演示缓存的代理 

  //当缓存被移除的时候执行
- (void)cache:(NSCache *)cache willEvictObject:(id)obj{NSLog(@"缓存移除  %@",obj);}

常见面试题

a. 默认缓存的时间_maxCacheAge = kDefaultCacheMaxCacheAge;
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 weekb. 使用的缓存对象_memCache = [[NSCache alloc] init];c. SDImageCache内处理内存警告,以通知的方式,clearMemoryd. cleanDisk的执行过程
i. 先遍历所有的缓存文件,记录过期的文件,计算缓存文件的总大小
ii. 删除过期的文件
iii. 判断maxCacheSize的值是否>0,如果大于0再判断缓存的文件总大小是否大于maxCacheSize
iv.如果缓存文件的总大小超过maxCacheSize,删除最早的文件1. SDWebImage的最大并发数是多少?
SDWebImageDownloader.m中的init方法
_downloadQueue.maxConcurrentOperationCount = 6;2. SDWebImage支持gif么?
支持。UIImage+GIF3. SDWebImage中怎么判断文件的类型的
NSData+ImageContentType.m中
根据文件头的第一个字节判断的case 0xFF:return @"image/jpeg";case 0x89:return @"image/png";case 0x47:return @"image/gif";case 0x49:case 0x4D:return @"image/tiff";4. SDWebImage缓存文件名称
为了防止缓存的图片名称冲突,根据md5计算的
md5重复的几率很小很小很小很小
终端中测试:echo -n  "图片路径" | md5

 

http://www.ngui.cc/el/3419340.html

相关文章

ios基础篇(十六)—— 网络之sockct

一、网络基本概念 客户端&#xff1a;应用 C/S B/S服务器&#xff1a;为客户端提供服务、数据、资源的机器请求&#xff1a;客户端向服务器索取数据响应&#xff1a;服务器对客户端的请求作出反应&#xff0c;一般是返回给客户端数据服务器 内网服务器外网服务器本地测试服…

时序图

一、时序图简介&#xff08;Brief introduction&#xff09; 时序图&#xff08;Sequence Diagram&#xff09;是显示对象之间交互的图&#xff0c;这些对象是按时间顺序排列的。 顺序图中显示的是参与交互的对象及其对象之间消息交互的顺序。 时序图中包括的建模元素主要有&a…

《Objective-C高级编程:iOS与OS X多线程和内存管理》 一 自动引用计数

一、自动引用计数 1.1 内存管理的思考方式 对象操作与objective-c 方法的对应对象操作Object-C 方法生成并持有对象alloc、new、copy、mutableCopy持有对象retain方法释放对象release方法废弃对象dealloc方法1.1.1 自己生成的对象&#xff0c;自己持有 使用以下名称开头的方…

《Objective-C高级编程:iOS与OS X多线程和内存管理》 一 Blocks模式GCD

一、Blocks摘要 Blocks&#xff1a;带有自动变量&#xff08;局部变量&#xff09;的匿名函数。 匿名函数&#xff1a;不带有名称的函数。 int func(int cout); //声明名称为func的函数 int result func(10); // 调用该函数&#xff0c;必须使用该函数的名称 // 若像下面这…

JXCategoryTitleView的使用

最近写项目&#xff0c;遇到了一个vc下面有多个vc 指示器可以点击切换&#xff0c;也可也左右滑动进行切换&#xff0c;解除了JXCategoryTitleView 感觉很好用&#xff1b; 一般要求主vc遵循JXCategoryViewDelegate、JXCategoryListContainerViewDelegate两个协议 子vc遵循JX…

基本编程能力练习

一、首先下载Java的编译环境并安装 JDK下载地址&#xff1a;https://www.oracle.com/java/technologies/javase-jdk15-downloads.html 选择适合自己系统的版本进行安装 这里我选择的是jdk-15_windows-x64_bin.exe 下载完成后直接运行安装&#xff0c;安装位置选择默认的C盘&am…

基本任务1.1Java语言基础

一、任务要求 完成基本数据类型的使用。完成基本运算符和表达式的使用。完成基本控制语句&#xff1a;判断、分支、循环等语句的使用。完成数组的使用。所有源代码必须加入行一级注释。 二、任务的理解 本次任务是让我们对Java编程中所遇到的基础知识进行学习和掌握&#xf…

基本任务1.1Java语言基础(任务挑战)

任务挑战&#xff1a; 1.编制一个Java application应用程序&#xff0c;把数组中已知的10个数字由小到大排序后输出。 编程前思考&#xff1a; 完成数组排序的方法有多种&#xff0c;其中有调用Arrays类中的sort方法直接对数组进行由小到大的排序&#xff0c;还可以采用冒泡排序…

基本任务1.2Java面向对象程序

一、任务要求 完成一个Java application应用程序&#xff0c;描述一个人类。要求如下&#xff1a;要求此人类必须包含有人的姓名、性别、出生日期等基本属性&#xff08;变量&#xff09;。要求此人类描述吃饭的方法&#xff08;函数&#xff09;和描述睡觉的方法&#xff08;…

基本任务1.3Java API

完成一个 java application应用程序&#xff0c;可以接收用户通过键盘输入的文本&#xff0c;并输出此段文本字符的个数。 代码&#xff1a; package task; //包名 import java.util.Scanner; //导入Scanner类 public class JavaAPI { //创建类public static void…