ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kingfisher 常见任务实战指南:从图片加载到缓存、下载、处理与序列化的完整方案

Kingfisher 常见任务实战指南:从图片加载到缓存、下载、处理与序列化的完整方案 Kingfisher 常见任务实战指南从图片加载到缓存、下载、处理与序列化的完整方案【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/KingfisherKingfisher 是一个纯 Swift 实现的轻量级图片下载与缓存框架本文以官方「Common Tasks」文档为主线系统讲解其最常用的开发任务基于视图扩展的一行式图片设置、占位图与加载指示器、缓存读写与容量/过期策略、手动下载与请求定制、图片处理器与自定义序列化器。读完本文你将掌握 Kingfisher 面向UIImageView、NSImageView、UIButton、NSButton等视图的标准用法并能根据业务需要定制缓存键、处理器与请求行为。概览一段代码解决绝大多数场景Kingfisher 的官方「Common Tasks」文档Sources/Documentation.docc/CommonTasks/CommonTasks.md给出了一个面向最常见任务的开箱即用代码片段你可以自由地将其整合进自己的项目。该片段主要面向 iOS 开发但只需极少的改动即可适配 macOS、tvOS 等其他平台——典型做法是替换具体类名例如将UIImage换成NSImage。从源码结构看Kingfisher 的整个图片加载体系可以抽象为三层视图扩展层UIImageView、NSImageView、UIButton、NSButton、NSTextAttachment等类型通过kf命名空间暴露setImage等便捷方法见 Sources/Extensions/ImageViewKingfisher.swift统一入口层KingfisherManager连接下载器与缓存对外提供retrieveImage系列方法见 Sources/General/KingfisherManager.swift基础设施层ImageCache内存 磁盘混合缓存见 Sources/Cache/ImageCache.swift与ImageDownloader封装URLSession见 Sources/Networking/ImageDownloader.swift。主文档将后续的深度专题拆分为四篇子文档本文会完整继承并逐节展开Common Tasks - CacheCommon Tasks - DownloaderCommon Tasks - ProcessorCommon Tasks - Serializer最常用任务从 URL 设置图片官方推荐将基于视图扩展的 APIUIImageView、NSImageView、UIButton、NSButton作为首选方案它们能让代码更简洁优雅。使用 URL 设置图片let url URL(string: https://example.com/image.jpg) imageView.kf.setImage(with: url)这段代码背后依次执行了以下动作以url.absoluteString作为键cache key检查图片是否已缓存若命中缓存内存或磁盘取出并赋值给imageView.image若未命中则发起请求从url下载将下载的数据转换为UIImage将图片同时存入内存缓存与磁盘缓存用新图片更新imageView.image。之后使用相同 URL 再次调用setImage只会执行第 1、2 步除非缓存被清除。这一行为在 KingfisherManager.swift 的retrieveImage私有实现中可以得到印证先经retrieveImageFromCache查询缓存命中则直接回调未命中且未开启onlyFromCache时才走loadAndCacheImage下载并回写缓存。注意setImage会执行 UI 变更需要在主线程调用progressBlock与completionHandler也会在主线程回调。setImage方法本身返回一个DownloadTask可用于后续取消下载。显示占位图Placeholderlet image UIImage(named: default_profile_icon) imageView.kf.setImage(with: url, placeholder: image)下载期间imageView会一直显示占位图。除了直接传图片你还可以让任意自定义UIView/NSView遵循Placeholder协议后作为占位视图class MyView: UIView { /* Implementation of your view */ } extension MyView: Placeholder { /* This can be left empty */ } imageView.kf.setImage(with: url, placeholder: MyView())MyView实例会按需被动态添加到imageView或从中移除。其底层机制在 Sources/Image/Placeholder.swift 中Placeholder协议要求实现add(to:)与remove(from:)两个方法KFCrossPlatformImage与KFCrossPlatformViewUIView/NSView都有默认实现——视图类占位符会被作为子视图添加到图片视图中央并撑满尺寸。下载时显示加载指示器imageView.kf.indicatorType .activity imageView.kf.setImage(with: url)这会在图片视图中央显示一个UIActivityIndicatorView。indicatorType支持多种取值见 ImageViewKingfisher.swift 中indicatorType的计算属性.none不显示任何指示器默认值.activity系统菊花指示器ActivityIndicator.image(data:)用指定图片数据构造ImageIndicator.custom(anIndicator)自定义遵循Indicator协议的指示器。指示器视图默认被居中约束到图片视图上并支持intrinsicSize、full、size(_:)三种尺寸策略。淡入显示下载完成的图片imageView.kf.setImage(with: url, options: [.transition(.fade(0.2))])图片下载完成后以 0.2 秒的淡入动画呈现。结合 ImageViewKingfisher.swift 的needsTransition实现可以知道默认只在缓存未命中.cacheType .none即真正下载了图片时才播放转场动画命中缓存时直接赋值如需在缓存命中时也强制动画可配合.forceTransition选项。使用 Completion Handler 获取结果imageView.kf.setImage(with: url) { result in // result is either a .success(RetrieveImageResult) or a .failure(KingfisherError) switch result { case .success(let value): // The image was set to image view: print(value.image) // From where the image was retrieved: // - .none - Just downloaded. // - .memory - Got from memory cache. // - .disk - Got from disk cache. print(value.cacheType) // The source object which contains information like url. print(value.source) case .failure(let error): print(error) // The error happens } }RetrieveImageResult的定义在 KingfisherManager.swift 中包含image、cacheType、source、originalSource以及懒加载的data闭包。cacheType的三种取值对应 ImageCache.swift 中的CacheType枚举.none刚下载、.memory来自内存缓存、.disk来自磁盘缓存。只取图、不设 UI使用 KingfisherManager有些场景只需要用 Kingfisher 获取图片而不赋值给任何视图此时应使用KingfisherManager.shared.retrieveImage(with:options:progressBlock:)KingfisherManager.shared.retrieveImage(with: url) { result in // Do something with result }KingfisherManager同时提供了 Swift Concurrency 版本async throws - RetrieveImageResult在 Swift 5.5 项目中可以直接try await调用取消外层Task会自动取消底层下载任务。缓存管理任务Common Tasks - CacheKingfisher 使用混合式ImageCache管理缓存同时包含内存存储与磁盘存储并对外提供高层管理 API。除非另行指定全框架统一使用ImageCache.default单例。其默认实现在 Sources/Cache/ImageCache.swift 中内部由MemoryStorage.BackendImage与DiskStorage.BackendData组成。使用自定义缓存键默认情况下URL 会被转换成字符串作为缓存键网络 URL 使用absoluteString。你可以通过创建带指定 key 的ImageResource来定制键let resource ImageResource( downloadURL: url, cacheKey: my_cache_key ) imageView.kf.setImage(with: resource)Kingfisher 使用cacheKey在缓存中定位图片因此请务必为每张不同的图片使用不同的键。ImageResource定义于 Sources/General/ImageSource/Resource.swift遵循Resource协议要求提供cacheKey与downloadURL。检查图片是否已缓存let cache ImageCache.default let cached cache.isCached(forKey: cacheKey) // To know where the cached image is: let cacheType cache.imageCachedType(forKey: cacheKey) // .memory, .disk or .none.imageCachedType(forKey:processorIdentifier:forcedExtension:)的实现见 ImageCache.swift会先查内存存储再查磁盘存储返回CacheType。若检索时应用了处理器处理后的图片会被缓存此时操作缓存也必须带上处理器标识符let processor RoundCornerImageProcessor(cornerRadius: 20) imageView.kf.setImage(with: url, options: [.processor(processor)]) // Later cache.isCached(forKey: cacheKey, processorIdentifier: processor.identifier)背后的原因是缓存键由key与processorIdentifier共同计算得出key.computedKey(with: identifier)处理后的图片与原始图片在磁盘上是两个不同的缓存文件。从缓存中获取图片cache.retrieveImage(forKey: cacheKey) { result in switch result { case .success(let value): print(value.cacheType) // If the cacheType is .none, image will be nil. print(value.image) case .failure(let error): print(error) } }retrieveImage(forKey:options:callbackQueue:completionHandler:)内部先查内存缓存命中则直接返回.memory未命中再异步查磁盘命中后还会回写内存便于下次快速访问返回.disk两者都未命中返回.none。磁盘读取默认在专用 IO 队列上异步执行如需同步读取可使用loadDiskFileSynchronously选项。设置缓存容量上限内存存储可配置totalCostLimit总成本上限单位字节与countLimit条目数量上限// Limit memory cache size to 300 MB. cache.memoryStorage.config.totalCostLimit 300 * 1024 * 1024 // Limit memory cache to hold 150 images at most. cache.memoryStorage.config.countLimit 150内存缓存的默认totalCostLimit为设备总内存的 25%见 ImageCache.swift 中createMemoryStorage()的实现ProcessInfo.processInfo.physicalMemory / 4默认不限制countLimit。磁盘存储可配置sizeLimit来限制文件系统占用// Limit disk cache size to 1 GB. cache.diskStorage.config.sizeLimit 1000 * 1024 * 1024磁盘缓存的默认sizeLimit为 0不限制。超出上限后cleanExpiredDiskCache会调用removeSizeExceededValues()清理超限文件。设置默认过期时间内存与磁盘存储各有默认过期策略内存中的图片在最近一次访问后 5 分钟过期磁盘中的图片 1 周后过期。可以这样修改// Set memory image expires after 10 minutes. cache.memoryStorage.config.expiration .seconds(600) // Set disk image never expires. cache.diskStorage.config.expiration .never也可以在单次设置图片时用选项覆盖某张图的过期策略// This image will never expire in memory cache. imageView.kf.setImage(with: url, options: [.memoryCacheExpiration(.never)])内存缓存默认每 2 分钟清理一次过期数据可调整清理间隔// Check memory clean up every 30 seconds. cache.memoryStorage.config.cleanInterval 30手动存储图片到缓存视图扩展方法与KingfisherManager默认会自动将取回的图片存入缓存但你也可以手动存储let image: UIImage //... cache.store(image, forKey: cacheKey)如果手里有图片的原始数据把它一并传给ImageCache有助于 Kingfisher 判断正确的存储格式let data: Data //... let image: UIImage //... cache.store(image, original: data, forKey: cacheKey)在store(_:original:forKey:options:toDisk:completionHandler:)的实现中可以看到内存写入是同步的storeNoThrow不会失败磁盘写入则在 IO 队列异步执行且磁盘数据由options.cacheSerializer默认DefaultCacheSerializer负责序列化original数据会被转发给序列化器用于判断图片格式。手动移除缓存Kingfisher 自动管理缓存但你仍可手动移除某张图片cache.removeImage(forKey: cacheKey)或进行更精细的控制cache.removeImage( forKey: cacheKey, processorIdentifier: processor.identifier, fromMemory: false, fromDisk: true) { print(Removed!) }removeImage支持分别控制是否从内存fromMemory与磁盘fromDisk移除并可传入processorIdentifier精确定位处理后的缓存项。清空缓存// Remove all. cache.clearMemoryCache() cache.clearDiskCache { print(Done) } // Remove only expired. cache.cleanExpiredMemoryCache() cache.cleanExpiredDiskCache { print(Done) }磁盘清理是异步操作在ioQueue上执行完成后在主线程回调。cleanExpiredDiskCache同时执行「过期清理」与「超限清理」若有文件被移除会通过KingfisherDidCleanDiskCache通知广播被清理文件的 hash 列表见 ImageCache.swift 开头的Notification.Name扩展。在 iOS 上ImageCache还会自动监听内存警告、进入后台等系统通知自动执行相应清理如UIApplication.didReceiveMemoryWarningNotification触发clearMemoryCache、didEnterBackgroundNotification触发backgroundCleanExpiredDiskCache。报告磁盘缓存大小ImageCache.default.calculateDiskStorageSize { result in switch result { case .success(let size): print(Disk cache size: \(Double(size) / 1024 / 1024) MB) case .failure(let error): print(error) } }calculateDiskStorageSize返回磁盘存储的总字节数在内部 IO 队列计算完毕后于主线程回调。创建并使用自己的缓存// The name parameter is used to identify the disk cache bound to the ImageCache. let cache ImageCache(name: my-own-cache) imageView.kf.setImage(with: url, options: [.targetCache(cache)])name用于标识该缓存绑定的磁盘缓存目录。注意ImageCache.default的name保留为default自定义缓存不要使用该名称否则不同缓存会互相污染。跳过缓存查找强制重新下载imageView.kf.setImage(with: url, options: [.forceRefresh])对应 KingfisherManager.swift 中retrieveImage的逻辑forceRefresh为true时直接走loadAndCacheImage完全不查询缓存下载完成后仍会写回缓存。只查缓存不存在的图片不下载这可以让应用进入「离线模式」imageView.kf.setImage(with: url, options: [.onlyFromCache])若图片不在缓存中会触发KingfisherError/CacheErrorReason/imageNotExisting(key:)错误。对应源码逻辑缓存未命中且onlyFromCache为true时直接以imageNotExisting错误回调。等待缓存完成waitForCache磁盘缓存是异步的在视图扩展方法中图片写入磁盘并不需要等到赋值与 completion handler 回调完成。这意味着 completion handler 执行时磁盘缓存可能尚未完全更新imageView.kf.setImage(with: url) { _ in ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) { result in switch result { case .success(let image): // image might be nil here. case .failure: break } } }多数场景下这种异步行为没有问题但如果你的逻辑依赖磁盘缓存已就绪请使用.waitForCache选项。启用后 Kingfisher 会推迟 handler 的执行直到磁盘缓存操作完成imageView.kf.setImage(with: url, options: [.waitForCache]) { _ in ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) { result in switch result { case .success(let image): // image exists. case .failure: break } } }这一点只适用于涉及异步 I/O 的磁盘缓存内存缓存操作是同步的完成回调时内存缓存中的图片一定可用。waitForCache的协调逻辑在 KingfisherManager.swift 的CacheCallbackCoordinator中实现它会等「缓存图片」与「缓存原始图」两个动作都完成或按需后才触发最终回调。下载任务Common Tasks - DownloaderImageDownloader封装了URLSession用于从网络下载图片。与ImageCache类似框架提供ImageDownloader.default供全局使用。其内部使用URLSessionConfiguration.ephemeral不持久化系统级缓存并默认请求策略为reloadIgnoringLocalCacheData。手动下载一张图片通常情况下你会优先使用视图扩展方法或KingfisherManager取图——它们会先查缓存以避免不必要的下载。如果需要跳过缓存直接下载图片可以这样let downloader ImageDownloader.default downloader.downloadImage(with: url) { result in switch result { case .success(let value): print(value.image) case .failure(let error): print(error) } }ImageLoadingResult中除了image还携带原始请求url与原始二进制数据originalData见 ImageDownloader.swift。发送前修改请求当图片资源有权限控制时可以使用.requestModifier(_:)定制请求let modifier AnyModifier { request in var r request r.setValue(abc, forHTTPHeaderField: Access-Token) return r } downloader.downloadImage(with: url, options: [.requestModifier(modifier)]) { result in // ... } // This option also works for view extension methods. imageView.kf.setImage(with: url, options: [.requestModifier(modifier)])在 ImageDownloader.swift 的createDownloadContext中可以看到Kingfisher 先构造默认URLRequest默认超时 15 秒、可启用 HTTP pipelining再由请求修饰器改写后发送若修饰器把 URL 改成了空值会以requestError(reason: .invalidURL)失败。使用异步请求修饰器如果修改请求前需要执行异步操作可以创建遵循AsyncImageDownloadRequestModifier的类型class AsyncModifier: AsyncImageDownloadRequestModifier { var onDownloadTaskStarted: ((DownloadTask?) - Void)? func modified(for request: URLRequest, reportModified: escaping (URLRequest?) - Void) { var r request someAsyncOperation { result in r.someProperty result.property reportModified(r) } } }同样通过.requestModifier(_:)应用该修饰器。此时setImage(with:placeholder:options:progressBlock:completionHandler:)或downloadImage(with:options:completionHandler:)不再直接返回DownloadTask——因为下载任务不会立刻启动。要拿到任务引用请监听AsyncImageDownloadRequestModifier.onDownloadTaskStarted回调let modifier AsyncModifier() modifier.onDownloadTaskStarted { task in if let task task { print(A download task started: \(task)) } } let nilTask imageView.kf.setImage(with: url, options: [.requestModifier(modifier)])这一行为在downloadImage的实现中可以看到使用同步修饰器时downloadTask会链接到真实任务使用异步修饰器时真实任务在异步回调完成后才创建并通过modifier.onDownloadTaskStarted?(downloadTask)通知。取消下载任务下载开始后会创建并返回一个DownloadTask可用来取消进行中的下载let task downloader.downloadImage(with: url) { result in // ... case .failure(let error): print(error.isTaskCancelled) // true } } // After some time, but before the download task completes. task?.cancel()如果任务已经完成再调用cancel()不会产生任何效果。视图扩展方法同样返回DownloadTask你可以保存并取消let task imageView.kf.set(with: url) task?.cancel()也可以对图片视图调用cancelDownloadTask()来取消当前正在进行的下载任务let task1 imageView.kf.set(with: url1) let task2 imageView.kf.set(with: url2) imageView.kf.cancelDownloadTask() // task2 will be cancelled, but task1 is still running. // However, the downloaded image for task1 will not be set because the image view expects a result from url2.task2会被取消而task1仍在运行不过即使task1下载完成其结果也不会被设置到图片视图上因为视图期望的是url2的结果。这一机制由 ImageViewKingfisher.swift 中的taskIdentifier实现每次setImage会生成新标识符旧任务完成时因标识符不匹配而被判定为notCurrentSourceTask丢弃。使用 NSURLCredential 进行认证ImageDownloader收到服务器 challenge 时默认采用.performDefaultHandling。要提供自定义凭证请配置authenticationChallengeResponder// In ViewController ImageDownloader.default.authenticationChallengeResponder self extension ViewController: AuthenticationChallengeResponsable { var disposition: URLSession.AuthChallengeDisposition { /* */ } let credential: URLCredential? { /* */ } func downloader( _ downloader: ImageDownloader, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) - Void) { // Provide your AuthChallengeDisposition and URLCredential completionHandler(disposition, credential) } func downloader( _ downloader: ImageDownloader, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: escaping (URLSession.AuthChallengeDisposition, URLCredential?) - Void) { // Provide your AuthChallengeDisposition and URLCredential completionHandler(disposition, credential) } }协议定义在 Sources/Networking/AuthenticationChallengeResponsable.swift。另外ImageDownloader还提供trustedHosts属性用于放行自签名站点的 server trust challenge仅当未设置authenticationChallengeResponder时生效。自定义超时时间请求的默认下载超时是 15 秒源码中_downloadTimeout: TimeInterval 15.0。可以为整个下载器定制// Set the timeout to 1 minute. downloader.downloadTimeout 60也可以为单个请求用.requestModifier(_:)定制let modifier AnyModifier { request in var r request r.timeoutInterval 60 return r } downloader.downloadImage(with: url, options: [.requestModifier(modifier)])图片处理器任务Common Tasks - ProcessorImageProcessor用于把一张图片或数据转换成另一张图片。在设置图片时把处理器交给KingfisherManager它会被应用到下载得到的数据上处理后的图片会同时发送给图片视图并存入缓存。使用默认处理器// Just without anything imageView.kf.setImage(with: url) // It equals to imageView.kf.setImage(with: url, options: [.processor(DefaultImageProcessor.default)])DefaultImageProcessor负责把下载数据转换为对应的图片对象默认支持 PNG、JPEG 与 GIF 格式。其定义在 Sources/Image/ImageProcessor.swiftidentifier为空字符串因此它是缓存的基准键。内置处理器一览Kingfisher 内置了丰富的处理器可直接通过.processor(_:)选项传入视图扩展方法// Round corner let processor RoundCornerImageProcessor(cornerRadius: 20) // Downsampling let processor DownsamplingImageProcessor(size: CGSize(width: 100, height: 100)) // Cropping let processor CroppingImageProcessor(size: CGSize(width: 100, height: 100), anchor: CGPoint(x: 0.5, y: 0.5)) // Blur let processor BlurImageProcessor(blurRadius: 5.0) // Overlay with a color fraction let processor OverlayImageProcessor(overlay: .red, fraction: 0.7) // Tint with a color let processor TintImageProcessor(tint: .blue) // Adjust color let processor ColorControlsProcessor(brightness: 1.0, contrast: 0.7, saturation: 1.1, inputEV: 0.7) // Black White let processor BlackWhiteProcessor() // Blend (iOS) let processor BlendImageProcessor(blendMode: .darken, alpha: 1.0, backgroundColor: .lightGray) // Compositing let processor CompositingImageProcessor(compositingOperation: .darken, alpha: 1.0, backgroundColor: .lightGray) // Use the process in view extension methods. imageView.kf.setImage(with: url, options: [.processor(processor)])各处理器均依据自身参数生成稳定的identifier例如RoundCornerImageProcessor的标识符由半径、目标尺寸、圆角集合与背景色共同决定见 ImageProcessor.swift从而保证处理结果可以被正确缓存与命中。BlendImageProcessor仅适用于 iOSCG-based 图片macOS 上对应的是CompositingImageProcessor。串联多个处理器// First blur the image, then make it round cornered. let processor BlurImageProcessor(blurRadius: 4) | RoundCornerImageProcessor(cornerRadius: 20) imageView.kf.setImage(with: url, options: [.processor(processor)])|运算符是append(another:)的语法糖见 ImageProcessor.swift组合后的处理器会先处理原数据再把结果作为.image输入交给下一个处理器新处理器标识符为\(self.identifier)|\(another.identifier)。创建自定义处理器实现ImageProcessor协议需要提供identifier与process(item:options:)struct MyProcessor: ImageProcessor { let someValue: Int var identifier: String { com.yourdomain.myprocessor-\(someValue) } // Convert input data/image to target image and return it. func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) - Image? { switch item { case .image(let image): // A previous processor already converted the image to an image object. // You can do whatever you want to apply to the image and return the result. return image case .data(let data): // Your own way to convert some data to an image. return createAnImage(data: data) } } }重要identifier用于在应用该处理器时确定缓存键。对于属性/功能相同的处理器必须保持identifier一致否则处理后的图片将无法命中缓存。文档与源码ImageProcessor.swift都建议避免使用空字符串作为自定义处理器的标识符空串被DefaultImageProcessor保留推荐使用反向域名表示法。然后把它传给setImage系列方法let processor MyProcessor(someValue: 10) let url URL(string: https://example.com/my_image.png) imageView.kf.setImage(with: url, options: [.processor(processor)])ImageProcessItem的.image分支意味着上游处理器已经把数据转成了图片你可以直接对图片做任意处理.data分支则需要自行把原始数据转换为图片处理失败时返回nil整个处理流程会终止并报告错误。从 CIFilter 快速创建处理器如果已经有现成的CIFilter可以实现CIImageProcessor协议快速创建处理器struct MyCIFilter: CIImageProcessor { let identifier com.yourdomain.myCIFilter let filter Filter { input in guard let filter CIFilter(name: xxx) else { return nil } filter.setValue(input, forKey: kCIInputBackgroundImageKey) return filter.outputImage } }CIImageProcessor的filter属性接收一个CIImage输入返回经过 Core Image 滤镜处理的CIImage输出底层桥接代码见 Sources/Image/Filter.swift。缓存序列化任务Common Tasks - SerializerCacheSerializer负责两件事从磁盘缓存读取时把数据转换为图片对象写入磁盘缓存时把图片存储为数据。使用默认序列化器// Just without anything imageView.kf.setImage(with: url) // It equals to imageView.kf.setImage(with: url, options: [.cacheSerializer(DefaultCacheSerializer.default)])DefaultCacheSerializer负责缓存数据与图片对象之间的互相转换默认支持 PNG、JPEG 与 GIF 格式。其实现见 Sources/Cache/CacheSerializer.swift存储时依据原始数据推断格式所以把original数据传给store有助于保持格式并支持背景解码选项。强制指定格式要强制某种图片格式可使用FormatIndicatedCacheSerializer它为所有支持格式提供了现成实例.png、.jpeg、.gif。圆角图片请使用 PNG 序列化器DefaultCacheSerializer会尽力保留输入图片数据的原始格式但有些场景下这不合适。例如使用RoundCornerImageProcessor时通常希望保留圆角周围的透明通道JPEG 没有 alpha 通道保存后再加载会丢失透明圆角。要确保 alpha 通道存在把图片转成 PNG请显式指定 PNG 序列化器let roundCorner RoundCornerImageProcessor(cornerRadius: 20) imageView.kf.setImage(with: url, options: [.processor(roundCorner), .cacheSerializer(FormatIndicatedCacheSerializer.png)] )FormatIndicatedCacheSerializer的实现见 Sources/Cache/FormatIndicatedCacheSerializer.swiftRoundCornerImageProcessor的文档注释ImageProcessor.swift也明确提示了「处理结果带 alpha 通道、但磁盘默认保留原格式会丢透明」这一坑并推荐用 PNG 序列化器规避。创建自定义序列化器实现CacheSerializer协议需要提供data(with:original:)与image(with:options:)struct MyCacheSerializer: CacheSerializer { func data(with image: Image, original: Data?) - Data? { return MyFramework.data(of: image) } func image(with data: Data, options: KingfisherParsedOptionsInfo?) - Image? { return MyFramework.createImage(from: data) } }然后传给setImage系列方法let serializer MyCacheSerializer() let url URL(string: https://yourdomain.com/example.png) imageView.kf.setImage(with: url, options: [.cacheSerializer(serializer)])延伸阅读主文档还推荐了以下专题可在仓库文档目录中继续深入图片预取PrefetchImageDataProvider本地文件、LivePhoto、PHPicker 等非网络图片来源加载指示器Indicator重试策略Retry低数据模式Low Data Mode性能优化建议Performance Tips结合官方 GettingStarted.md 与 Demo 工程Demo/Kingfisher-Demo中的示例控制器如 NormalLoadingViewController.swift、ProcessorCollectionViewController.swift可以快速验证本文涉及的各项 API 的实际效果。【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表