PINRemoteImage

快速、无死锁的并行图像下载器和缓存,适用于 iOS

CocoaPods compatible Carthage compatible Build status

PINRemoteImageManager 是一个图像下载、处理和缓存管理器。它使用下载和处理任务的概念来确保即使多次调用下载或处理图像,也只会发生一次(除非项目不再在缓存中)。PINRemoteImageManager 由 GCD 支持,并且可以安全地从多个线程同时访问。它确保图像在主线程之外解码,以便动画性能不受影响。它的所有公开方法都不允许同步访问。但是,如果项目在其内存缓存中,则它已优化为在调用线程上调用完成处理程序。

PINRemoteImage 支持下载多种类型的文件。当然,它支持 PNGJPG。如果 Google 的库可用,它还支持解码 WebP 图像。它甚至通过 PINAnimatedImageView 支持 GIF动画 WebP

PINRemoteImage 还有两种方法可以改善在慢速网络连接上下载图像的体验。第一种是对渐进式 JPG 的支持。但这不仅仅是对渐进式 JPG 的普通支持:PINRemoteImage 在返回渐进式扫描之前,会为其添加有吸引力的模糊效果。

Progressive JPG with Blur

PINRemoteImageCategoryManager 定义了一个协议,UIView 子类可以实现该协议,并提供对 PINRemoteImageManager 方法的轻松访问。在 UIImageViewPINAnimatedImageViewUIButton 上有内置类别,并且非常容易实现新类别。有关现有类别的参考,请参阅 [UIImageView+PINRemoteImage](/Pod/Classes/Image Categories/UIImageView+PINRemoteImage.h)。

下载图像并将其设置在图像视图上

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/kitten.jpg"]];

Swift

let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/kitten.jpg")!)

下载渐进式 JPEG 并获取有吸引力的模糊更新

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView setPin_updateWithProgress:YES];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/progressiveKitten.jpg"]];

Swift

let imageView = UIImageView()
imageView.pin_updateWithProgress = true
imageView.pin_setImage(from: URL(string: "https://pinterest.com/progressiveKitten.jpg")!)

下载 WebP 文件

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/googleKitten.webp"]];

Swift

let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/googleKitten.webp")!)

下载 GIF 并使用 PINAnimatedImageView 显示

Objective-C

PINAnimatedImageView *animatedImageView = [[PINAnimatedImageView alloc] init];
[animatedImageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/flyingKitten.gif"]];

Swift

let animatedImageView = PINAnimatedImageView()
animatedImageView.pin_setImage(from: URL(string: "http://pinterest.com/flyingKitten.gif")!)

下载和处理图像

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[self.imageView pin_setImageFromURL:[NSURL URLWithString:@"https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg"] processorKey:@"rounded" processor:^UIImage *(PINRemoteImageManagerResult *result, NSUInteger *cost)
 {
     CGSize targetSize = CGSizeMake(200, 300);
     CGRect imageRect = CGRectMake(0, 0, targetSize.width, targetSize.height);
     UIGraphicsBeginImageContext(imageRect.size);
     UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:7.0];
     [bezierPath addClip];

     CGFloat sizeMultiplier = MAX(targetSize.width / result.image.size.width, targetSize.height / result.image.size.height);

     CGRect drawRect = CGRectMake(0, 0, result.image.size.width * sizeMultiplier, result.image.size.height * sizeMultiplier);
     if (CGRectGetMaxX(drawRect) > CGRectGetMaxX(imageRect)) {
         drawRect.origin.x -= (CGRectGetMaxX(drawRect) - CGRectGetMaxX(imageRect)) / 2.0;
     }
     if (CGRectGetMaxY(drawRect) > CGRectGetMaxY(imageRect)) {
         drawRect.origin.y -= (CGRectGetMaxY(drawRect) - CGRectGetMaxY(imageRect)) / 2.0;
     }

     [result.image drawInRect:drawRect];

     UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return processedImage;
 }];

Swift

let imageView = FLAnimatedImageView()
imageView.pin_setImage(from: URL(string: "https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg")!, processorKey: "rounded")  { (result, unsafePointer) -> UIImage? in

    guard let image = result.image else { return nil }

    let radius : CGFloat = 7.0
    let targetSize = CGSize(width: 200, height: 300)
    let imageRect = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height)

    UIGraphicsBeginImageContext(imageRect.size)

    let bezierPath = UIBezierPath(roundedRect: imageRect, cornerRadius: radius)
    bezierPath.addClip()

    let widthMultiplier : CGFloat = targetSize.width / image.size.width
    let heightMultiplier : CGFloat = targetSize.height / image.size.height
    let sizeMultiplier = max(widthMultiplier, heightMultiplier)

    var drawRect = CGRect(x: 0, y: 0, width: image.size.width * sizeMultiplier, height: image.size.height * sizeMultiplier)
    if (drawRect.maxX > imageRect.maxX) {
        drawRect.origin.x -= (drawRect.maxX - imageRect.maxX) / 2
    }
    if (drawRect.maxY > imageRect.maxY) {
        drawRect.origin.y -= (drawRect.maxY - imageRect.maxY) / 2
    }

    image.draw(in: drawRect)

    UIColor.red.setStroke()
    bezierPath.lineWidth = 5.0
    bezierPath.stroke()

    let ctx = UIGraphicsGetCurrentContext()
    ctx?.setBlendMode(CGBlendMode.overlay)
    ctx?.setAlpha(0.5)

    let logo = UIImage(named: "white-pinterest-logo")
    ctx?.scaleBy(x: 1.0, y: -1.0)
    ctx?.translateBy(x: 0.0, y: -drawRect.size.height)

    if let coreGraphicsImage = logo?.cgImage {
        ctx?.draw(coreGraphicsImage, in: CGRect(x: 90, y: 10, width: logo!.size.width, height: logo!.size.height))
    }

    let processedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return processedImage

}

处理身份验证

Objective-C

[[PINRemoteImageManager sharedImageManager] setAuthenticationChallenge:^(NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, PINRemoteImageManagerAuthenticationChallengeCompletionHandler aCompletion) {
aCompletion(NSURLSessionAuthChallengePerformDefaultHandling, nil)];

Swift

PINRemoteImageManager.shared().setAuthenticationChallenge { (task, challenge, completion) in
  completion?(.performDefaultHandling, nil)
}

支持高分辨率图像

目前 PINRemoteImage 支持高分辨率图像的方式有两种

  1. 如果 URL 包含 _2x._3x. 后缀,PINRemoteImage 将自动处理,并且生成的图像将以正确的比例返回。
  2. 如果无法提供带有 _2x._3x. 后缀的 URL,您还可以使用完成处理程序来处理它
NSURL *url = ...;
__weak UIImageView *weakImageView = self.imageView;
[self.imageView pin_setImageFromURL:url completion:^(PINRemoteImageManagerResult * _Nonnull result) {
  CGFloat scale = UIScreen.mainScreen.scale;
  if (scale > 1.0) {
    UIImage *image = result.image;
    weakImageView.image = [UIImage imageWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
    }
}];

设置一些限制

// cache is an instance of PINCache as long as you haven't overridden defaultImageCache
PINCache *cache = (PINCache *)[[PINRemoteImageManager sharedImageManager] cache];
// Max memory cost is based on number of pixels, we estimate the size of one hundred 600x600 images as our max memory image cache.
[[cache memoryCache] setCostLimit:600 * [[UIScreen mainScreen] scale] * 600 * [[UIScreen mainScreen] scale] * 100];

// ~50 MB
[[cache diskCache] setByteLimit:50 * 1024 * 1024];
// 30 days
[[cache diskCache] setAgeLimit:60 * 60 * 24 * 30];

安装

CocoaPods

PINRemoteImage 添加到您的 Podfile 并运行 pod install

如果您想使用 WebP 图像,请将 PINRemoteImage/WebP 添加到您的 Podfile 并运行 pod install

Carthage

github "pinterest/PINRemoteImage" 添加到您的 Cartfile 中。有关将 Carthage 构建的框架集成到您的项目中的更多信息,请参阅 Carthage 的 readme

手动

下载最新的 tag 并将 Pod/Classes 文件夹拖到您的 Xcode 项目中。您还必须手动链接 PINCache

通过双击 docs/ 下的 .docset 文件来安装文档,或者在 cocoadocs.org 在线查看它们

Git 子模块

您可以将 PINRemoteImage 设置为 repo 的子模块,而不是克隆和复制所有文件到您的 repo 中。使用以下命令添加子模块,然后按照上面的手动说明进行操作。

git submodule add https://github.com/pinterest/PINRemoteImage.git
git submodule update --init

要求

PINRemoteImage 需要 iOS 12.0 或更高版本。

联系方式

Garrett Moon @garrettmoon Pinterest

许可证

版权所有 2015 Pinterest, Inc.

根据 Apache License, Version 2.0(“许可证”)获得许可;除非遵守许可证,否则您不得使用此文件。您可以在以下网址获取许可证副本:https://apache.ac.cn/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则根据“按原样”基础分发的软件不附带任何形式的明示或暗示的保证或条件。有关管辖权限和限制的特定语言,请参阅许可证