ios基础篇(十五)—— SDWebImage

一、SDWebImage介绍

  • 什么是SDWebImage
    • iOS中著名的牛逼的网络图片处理框架
    • 包含的功能:图片下载、图片缓存、下载进度监听、gif处理等等
    • 用法极其简单,功能十分强大,大大提高了网络图片的处理效率
    • 国内超过90%的iOS项目都有它的影子
  • 项目地址
  • 下载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 创建可重用的cell
    static NSString *reuseId = @"appInfo";
    HMAppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId];
    //2 获取数据,给cell内部子控件赋值
    HMAppInfo *appInfo = self.appInfos[indexPath.row];    
    cell.appInfo = appInfo;
      //3 返回cell
    return 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) {
            //图片下载完成更新UI
            NSLog(@"更新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 week

b. 使用的缓存对象
 _memCache = [[NSCache alloc] init];

c. SDImageCache内处理内存警告,以通知的方式,clearMemory

d. cleanDisk的执行过程
i. 先遍历所有的缓存文件,记录过期的文件,计算缓存文件的总大小
ii. 删除过期的文件
iii. 判断maxCacheSize的值是否>0,如果大于0再判断缓存的文件总大小是否大于maxCacheSize
iv.如果缓存文件的总大小超过maxCacheSize,删除最早的文件

1. SDWebImage的最大并发数是多少?
SDWebImageDownloader.m中的init方法
_downloadQueue.maxConcurrentOperationCount = 6;

2. SDWebImage支持gif么?
支持。UIImage+GIF

3. 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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,作为一个 AI 语言模型,我无法提供文件的下载或共享链接。但我可以列举一些常用的 IOS 命令作为参考: 1. 查看接口信息 - show interfaces:查看接口的状态和统计信息。 - show ip interface brief:查看接口的 IP 地址和状态信息。 - show interface description:查看接口的描述信息。 2. 配置接口 - interface [interface-name]:进入接口配置模式。 - no shutdown:打开接口。 - shutdown:关闭接口。 - ip address [ip-address] [subnet-mask]:配置接口的 IP 地址和子网掩码。 - description [description]:配置接口的描述信息。 3. 配置 VLAN - vlan [vlan-id]:进入 VLAN 配置模式。 - name [vlan-name]:配置 VLAN 的名称。 - exit:退出 VLAN 配置模式。 - show vlan:查看 VLAN 的配置信息。 4. 配置交换机 - enable:进入特权模式。 - configure terminal:进入全局配置模式。 - hostname [hostname]:配置交换机的主机名。 - banner motd [delimiter] [message] [delimiter]:配置欢迎信息。 - interface vlan [vlan-id]:进入 VLAN 接口配置模式。 - ip address [ip-address] [subnet-mask]:配置 VLAN 接口的 IP 地址和子网掩码。 - ip default-gateway [ip-address]:配置默认网关。 - line console 0:进入控制台线路配置模式。 - password [password]:配置控制台密码。 - exit:退出控制台线路配置模式。 以上是一些常用的 IOS 命令,具体命令可以根据实际需要进行查找和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值