iOS 加载大图优化思路

热门标签

,

特别声明:文章多为网络转载,资源使用一般不提供任何帮助,特殊资源除外,如有侵权请联系!

场景:假如有一张非常大的图片,可能有500MB,也可能有1个G甚至更大。需要显示在我们的iOS设备,该怎样加载呢?
直接读取图片,加载到UIImageView会直接闪退。
苹果的开发者早就考虑到这个,给开发者提供了CATiledLayer了。CATiledLayer 为载入大图造成的性能问题提供了一个解决方案:将大图分解成小片然后将他们单独按需载入。在多个线程中为每个小块同时调用 -drawLayer:inContext: 方法。这就避免了阻塞用户交互而且能够利用多核心新片来更快地绘制。只有一个小块的 CATiledLayer 是实现异步更新图片视图的简单方法。

iOS 加载大图优化思路
加载大图优化.gif

案例中是一张2048*2048的图片,被分割成了64个256*256的小图,以Snowman_00_00-Snowman_07_07的规则命名。下面看CATiledLayer具体实现代码:

@interface CATiledLayerViewController ()<CALayerDelegate>
{
    CATiledLayer * _tileLayer;
}
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

@end

@implementation CATiledLayerViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    CATiledLayer *tileLayer = [CATiledLayer layer];
    _tileLayer = tileLayer;
    tileLayer.frame = CGRectMake(0, 0, 2048, 2048);
    tileLayer.delegate = self;
    tileLayer.drawsAsynchronously = YES;
    tileLayer.contentsScale = [UIScreen mainScreen].scale;
    [self.scrollView.layer addSublayer:tileLayer];
    //configure the scroll view
    self.scrollView.contentSize = tileLayer.frame.size;
        //draw layer
    [tileLayer setNeedsDisplay];         
}

- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)ctx
{
    //determine tile coordinate
    CGRect bounds = CGContextGetClipBoundingBox(ctx);
    CGFloat scale = [UIScreen mainScreen].scale;
    NSInteger x = floor(bounds.origin.x / layer.tileSize.width * scale);
    NSInteger y = floor(bounds.origin.y / layer.tileSize.height * scale);
    
    //load tile image
    NSString *imageName = [NSString stringWithFormat: @"Snowman_%02li_%02li", (long)x, (long)y];
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"];
    UIImage *tileImage = [UIImage imageWithContentsOfFile:imagePath];
    //draw tile
    UIGraphicsPushContext(ctx);
    [tileImage drawInRect:bounds];
    UIGraphicsPopContext();
}

- (void)dealloc{
    if (_tileLayer) {
        [_tileLayer removeFromSuperlayer];
        _tileLayer = nil;
    }
}

@end

使用CATiledLayer需要注意:
1.退出页面时需要移除_tileLayer对象
2.就算x,y时需要考虑屏幕分辩率

总结:
1.在真正的业务中,需要的肯定是网络图片。CATiledLayer可与SDWebImage结合使用,并发下载和图片缓存的问题不需要再考虑。同时结合RunLoop的优化特性,只在空闲时加载图片。以达到性能最优。
2.而图片的切割及命名,应该在上传的时候就应该考虑的,即使是1个G的图片,我们也能先显示部分再根据滑动加载。
3.像分辨率,图片大小及分割完的url数组可以在接口统一返回。

本文参考:《iOS CoreAnimation》

 

未经允许不得转载:作者:SheaYang, 转载或复制请以 超链接形式 并注明出处 技术Dog|博客
原文地址:《iOS 加载大图优化思路》 发布于2019-11-03

分享到:
赞(0) 打赏

评论 抢沙发

3 + 7 =


iOS 加载大图优化思路

长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.0主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?