ARTICLE DETAIL

资讯详情

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

Nuke 14 迁移指南:从 Nuke 13.x 升级的完整 API 变更与适配方案

Nuke 14 迁移指南:从 Nuke 13.x 升级的完整 API 变更与适配方案 移动开发图像处理【免费下载链接】NukeImage loading system项目地址https://gitcode.com/gh_mirrors/nu/Nuke点击查看免费下载本指南面向正在使用 Nuke 13.x 并准备升级到 Nuke 14 的开发者系统梳理了 Nuke 14 在模块结构、动画解析、API 命名、并发模型与 SwiftUI 集成方面的全部破坏性变更并给出可复制的迁移代码。阅读完成后你将能够把现有代码库平滑迁移到 Nuke 14理解NukeUI与ImageDisplaying的新职责边界掌握 Async/Await 时代下管线、任务与委托的用法并提前识别 Nuke 15 中即将移除的兼容层。说明Nuke 14 处于开发中Work in Progress本指南会随变更持续更新文中涉及的默认值与行为均以当前仓库源码为准。最低系统要求一次彻底的基础线提升Nuke 14 全面抬升了最低支持平台同时要求最新的 Apple 工具链平台最低版本iOS16.0tvOS16.0macOS13.0watchOS9.0visionOS1.0编译器与语言要求Xcode 26.0、Swift 6.2。仍需要支持更早系统版本的 App 可以继续停留在Nuke 13.x该分支会持续接收修复。这一基线提升是 Nuke 14 一系列结构性改动严格并发隔离、全 Swift Task 化的任务队列、移除旧 API的前提迁移前请先确认构建环境满足上表要求。NukeExtensions并入NukeUI三模块格局确立Nuke 14 将原本位于NukeExtensions的图片视图扩展整体迁入NukeUI——NukeUI本来就是 UIKit/AppKit 视图LazyImageView、AnimatedImageView等的所在地。调整后包只发布三个模块Nuke管线、解码、处理、缓存等核心能力NukeUI所有视图扩展与 SwiftUI 组件NukeVideo视频解码与播放AVDataAsset、VideoPlayerView。NukeExtensions目前仍以空模块的形式存在仅负责 re-exportNukeUI保证存量代码继续编译从源码注释看它计划在 Nuke 15 移除见 Sources/NukeExtensions/Exports.swift。因此新代码应直接改用NukeUI// Before import NukeExtensions // After import NukeUI如果此前按模块名引用了这些函数请同步更新前缀// Before NukeExtensions.loadImage(with: url, into: imageView) // After NukeUI.loadImage(with: url, into: imageView)Nuke_ImageDisplaying更名为ImageDisplaying拥抱整个ImageContainer协议签名变化Nuke 13 的Nuke_ImageDisplaying是objc协议方法接收拆开的image与data两个参数Nuke 14 中去掉了objc与前缀方法改为接收整个ImageContainer——管线解析出的动图数据就在这个容器里// Nuke 13 extension MyImageView: Nuke_ImageDisplaying { func nuke_display(image: UIImage?, data: Data?) { self.image image } } // Nuke 14 extension MyImageView: ImageDisplaying { func nuke_display(_ container: ImageContainer?) { self.image container?.image } }迁移对照关系image→container?.imagedata→container?.datanuke_display(image: nil, data: nil)清空视图→nuke_display(nil)需要播放动图时直接使用已解析好的container?.animation方法保留nuke_前缀是因为内置一致性conformance以系统类扩展extension的形式随包提供不带前缀的命名可能与未来的系统 API 冲突见 Sources/NukeUI/ImageViewExtensions.swift 的协议注释。ImageDisplayingViewiOS/tvOS/visionOS 上为UIView ImageDisplayingmacOS 上为NSObject ImageDisplaying保持不变。破坏性影响UIImageView 子类中重写显示方法不再生效Swift 对在扩展中声明的协议见证witness采取静态决议因此在UIImageView子类里 override 显示方法将永远不会被调用// Nuke 13 —— Nuke 14 中不再生效 final class MyImageView: UIImageView { override func nuke_display(image: UIImage?, data: Data?) { ... } }正确做法是让自定义视图直接声明一致性自己持有内部UIImageView// Nuke 14 final class MyImageView: UIView, ImageDisplaying { private let imageView UIImageView() func nuke_display(_ container: ImageContainer?) { imageView.image container?.image } }协议注释中给出了更贴近真实场景的写法渲染器可以从容器中同时拿到静态图与已解析的animation见 Sources/NukeUI/ImageViewExtensions.swiftfinal class MyImageView: UIView, ImageDisplaying { func nuke_display(_ container: ImageContainer?) { guard let animation container?.animation else { return show(still: container?.image) } myEngine.play(animation) } }如果子类的目的只是为了播放动图直接使用AnimatedImageView即可——它本身就继承了扩展中的ImageDisplaying一致性并在内部通过displayContainer(_:)将整个容器交给display(container)处理见 Sources/NukeUI/ImageViewExtensions.swift。管线开始解析动图ImageContainer.animation登场解析职责上移在 Nuke 13 中ImageDecoders.Default只是把动图的编码字节附加到ImageContainer.dataNuke 14 进一步解析这些数据并把结果放入新增的ImageContainer.animation类型为AnimatedImageSource。以展示动图为例// Nuke 13 guard let source AnimatedImageSource(data: response.container.data ?? Data()) else { return } // Nuke 14 guard let animation response.container.animation else { return }AnimatedImageSource从NukeUI移到了Nuke核心模块NukeUI会 re-exportNuke所以导入任一模块的既有代码都能继续编译。解析的时机、成本与关闭开关从默认解码器实现可以确认解析的具体行为见 Sources/Nuke/Decoding/ImageDecodersDefault.swift解码时先通过AssetType.isAnimated(data:type:)做头字节嗅探header sniff命中后再决定是否附加data解析AnimatedImageSource(data:)在解码队列上执行每张被解码的图像只解析一次结果随容器一起缓存解析会逐帧遍历元数据如每帧的 delay无论图像最终是否被显示成本都会发生。文档与源码注释都强调container.data ! nil只是头嗅探对单帧 GIF 也为true而container.animation ! nil才是能否播放的已解析答案判断可播放性时应优先使用它。如果 App 根本不需要播放动图或用自己的渲染引擎播放可以关闭解析ImagePipeline.shared ImagePipeline { $0.isAnimatedImageParsingEnabled false }该开关在ImagePipeline.Configuration中的默认值为true见 Sources/Nuke/Pipeline/ImagePipelineConfiguration.swift并通过ImageDecodingContext.isAnimatedImageParsingEnabled一路传到解码器见 Sources/Nuke/Decoding/ImageDecoderRegistry.swift。两条需要注意的关联行为ImageContainer.data不受该开关影响因此自己解析数据的渲染器不受干扰处理processing图像会同时清空data与animation——它们描述的是进入处理器之前的图像。ImageContainer.map(_:)的源码明确执行了copy.data nil; copy.animation nil见 Sources/Nuke/ImageContainer.swift。另外animation与data共享同一缓冲区AnimatedImageSource.data即data所以附加动画只额外增加帧延迟信息的内存成本见 Sources/Nuke/ImageContainer.swift。移除 Nuke 13 中已废弃的 APINuke 13 标记废弃的 API 在 Nuke 14 中全部移除完整对照如下移除替代方案ImagePipelineDelegateImagePipeline.DelegateImageRequest.imageIdImageRequest.imageIDImageRequest.UserInfoKey.imageIdKeyImageRequest.imageIDImageRequest.UserInfoKey.scaleKeyImageRequest.scaleImageRequest.UserInfoKey.thumbnailKeyImageRequest.thumbnailImagePipeline.Configuration.maximumDecodedImageSizeImageRequest.ThumbnailOptionsImageDecodingContext.maximumDecodedImageSizeImageRequest.ThumbnailOptions关于maximumDecodedImageSize其背后的自动降采样automatic downscaling实现早在 Nuke 13 就被移除所以在 Nuke 13 中设置它已经没有任何效果。Nuke 14 中请改用ImageRequest.ThumbnailOptions按请求per-request控制解码图像尺寸。ImageRequest初始化器移除userInfo参数userInfo参数在 Nuke 13 中已被软废弃Nuke 14 中从ImageRequest的初始化器中移除。原先经它传递的选项现在都有专用的类型安全属性scale、thumbnail等见 Sources/Nuke/ImageRequest.swiftuserInfo本身仍作为属性保留供自定义值使用// Before let request ImageRequest(url: url, userInfo: [key: value]) // After var request ImageRequest(url: url) request.userInfo [key: value]移除 Combine 支持全面转向 Async/AwaitNuke 14 移除了全部 Combine API改用 Async/Await移除替代方案ImagePipeline.imagePublisher(with:)ImagePipeline.image(for:)或ImagePipeline.imageTask(with:)FetchImage.load(_:)接收PublisherFetchImage.load(_:)接收 async 闭包典型迁移// Nuke 13 cancellable ImagePipeline.shared.imagePublisher(with: url) .sink(receiveCompletion: { _ in }, receiveValue: { response in imageView.image response.image }) // Nuke 14 imageView.image try await ImagePipeline.shared.image(for: url)原来由 publisher 作为中间值intermediate values发射的渐进解码预览改用ImageTask.previews观察FetchImage仍然是ObservableObject从 SwiftUI 中观察它的用法不变。移除ImageTask.Event.startedImageTask.Event.started从未投递给ImageTask.events——管线是直接向 delegate 报告的因此它实际上只为ImagePipeline.Delegate存在。Nuke 14 为 delegate 提供了专门方法// Nuke 13 func imageTask(_ task: ImageTask, didReceiveEvent event: ImageTask.Event, pipeline: ImagePipeline) { switch event { case .started: handleStart(task) case .progress, .preview, .finished: break } } // Nuke 14 func imageTaskDidStart(_ task: ImageTask, pipeline: ImagePipeline) { handleStart(task) }缩放与尺寸 APIFloat全面改为CGFloat公共的 scale 与 size API 统一改用CGFloat与 UIKit / SwiftUI 给出的类型对齐APINuke 13Nuke 14ImageRequest.scaleFloatCGFloatImageRequest.ThumbnailOptions.init(maxPixelSize:)FloatCGFloat字面量literal仍然可以直接赋值无需改动如果你之前写了显式转换现在可以删除// Nuke 13 request.scale Float(traitCollection.displayScale) // Nuke 14 request.scale traitCollection.displayScalewillCache变为asyncImagePipeline.Delegate.willCache(data:image:for:pipeline:)不再接收完成闭包而是直接返回要存储的数据返回nil表示禁止缓存// Nuke 13 func willCache(data: Data, image: ImageContainer?, for request: ImageRequest, pipeline: ImagePipeline, completion: escaping (Data?) - Void) { completion(shouldStore(request) ? data : nil) } // Nuke 14 func willCache(data: Data, image: ImageContainer?, for request: ImageRequest, pipeline: ImagePipeline) async - Data? { shouldStore(request) ? data : nil }该方法运行在ImagePipelineActor上见 Sources/Nuke/Pipeline/ImagePipelineDelegate.swift管线在存储数据前会等待它完成。TaskQueue.maxConcurrentOperationCount更名TaskQueue背后已经没有 OperationOperationQueue时代的产物——它的每一个工作单元都是 SwiftTask因此旧名字不再贴切。旧名字仍然可用但已标记废弃见 Sources/Nuke/Pipeline/TaskQueue.swiftNuke 13Nuke 14TaskQueue.maxConcurrentOperationCountTaskQueue.maxConcurrentTaskCountTaskQueue(maxConcurrentOperationCount:)TaskQueue(maxConcurrentTaskCount:)// Nuke 13 let pipeline ImagePipeline { $0.imageProcessingQueue.maxConcurrentOperationCount 4 } // Nuke 14 let pipeline ImagePipeline { $0.imageProcessingQueue.maxConcurrentTaskCount 4 }从源码看maxConcurrentTaskCount的默认值是ProcessInfo.processInfo.processorCount处理器核心数见 Sources/Nuke/Pipeline/TaskQueue.swift且队列内部用OSAllocatedUnfairLock保护的Limits状态管理并发与预留任务数见 Sources/Nuke/Pipeline/TaskQueue.swift。ImagePipeline.Delegate声明隔离isolationNuke 13 的 delegate 协议只在文档注释中描述方法运行位置performed on the pipeline queue in the background且该描述只对一半方法成立。Nuke 14 将隔离isolation直接写入每个方法的签名隔离方法ImagePipelineActorwillLoadData、willCache、imageTaskDidStart、imageTask(_:didReceiveEvent:)nonisolated其余所有工厂方法、cacheKey、策略方法、decompress、imageTaskCreated协议签名可参见 Sources/Nuke/Pipeline/ImagePipelineDelegate.swift。迁移影响很小普通无隔离声明方法依然能满足隔离要求因此大多数 conformer 无需改动只有带冲突隔离的方法才会被拒绝。此前无法通过一致性检查的MainActordelegate现在反而可以正常工作。FetchImage.Progress替换为ImageTask.ProgressNukeUI曾有自己的进度类型——一个嵌套在另一个ObservableObject里的ObservableObject必须用独立的ObservedObject去观察。现在FetchImage.progress与LazyImageState.progress都返回ImageTask.Progress——与管线报告的是同一个值类型且由FetchImage自己发布更新APINuke 13Nuke 14FetchImage.progress、LazyImageState.progressFetchImage.ProgressclassImageTask.Progressstruct// Nuke 13 LazyImage(url: url) { state in if state.isLoading { DownloadProgressView(progress: state.progress) } } struct DownloadProgressView: View { ObservedObject var progress: FetchImage.Progress var body: some View { ProgressView(value: progress.fraction) } } // Nuke 14 LazyImage(url: url) { state in if state.isLoading { ProgressView(value: state.progress.fraction) } }相关实现细节FetchImage.Progress现在是标记废弃的 typealias指向ImageTask.Progress见 Sources/NukeUI/Deprecated.swift并将在 Nuke 15 移除ImageTask.Progress是Hashable, Sendable的结构体见 Sources/Nuke/ImageTask.swift进度更新仅在读取progress时才发布读取该属性会让对象选择发布进度因此不展示进度的视图不会因为每个数据块到达而被无效化重绘见 Sources/NukeUI/FetchImage.swift。NukeUI直接暴露ImagePipeline.Error管线总是以ImagePipeline.Error结束每个任务因此NukeUI不再把它擦除成any Error。分支判断不再需要类型转换APINuke 13Nuke 14FetchImage.result、LazyImageState.resultResultImageResponse, any Error?ResultImageResponse, ImagePipeline.Error?FetchImage.onCompletion、LazyImage.onCompletion(_:)、LazyImageView.onCompletion(ResultImageResponse, any Error) - Void(ResultImageResponse, ImagePipeline.Error) - VoidLazyImageState.error、LazyImageView.onFailureany ErrorImagePipeline.Error// Nuke 13 LazyImage(url: url) { state in if let error state.error as? ImagePipeline.Error, case .dataDownloadExceededMaximumSize error { Text(Image too large) } } // Nuke 14 LazyImage(url: url) { state in if case .dataDownloadExceededMaximumSize state.error { Text(Image too large) } }LazyImage.onCompletion(_:)等闭包的签名变化与LazyImageState.error的类型收窄均可从源码确认见 Sources/NukeUI/LazyImage.swift。一个例外FetchImage.load(_:)仍接受无类型的 async 闭包。如果闭包抛出的错误不是ImagePipeline.Error会被包装成dataLoadingFailed(error:)报告——这与管线对 asyncImageRequest源抛错的报告方式一致。迁移自检清单升级到 Nuke 14 后建议按以下顺序排查存量代码模块导入把import NukeExtensions全部改为import NukeUI并按模块名调用的函数同步替换前缀自定义显示视图删除UIImageView子类中的nuke_display(image:data:)override改为在自定义UIView上直接声明ImageDisplaying并实现nuke_display(_ container: ImageContainer?)动图处理优先读取container.animation判断可播放性不播放动图的 App 可关闭isAnimatedImageParsingEnabled异步化将 Combine publisher 代码改写为image(for:)/imageTask(with:)ImageTask.previews把带完成闭包的 delegate 方法改为 async/await 形式类型与命名把Float相关转换删除、改用CGFloatTaskQueue使用maxConcurrentTaskCountImageRequest初始化器去掉userInfo参数错误与进度删除对any Error的强转直接匹配ImagePipeline.Error的 case用值类型的ImageTask.Progress替换ObservedObject var progress: FetchImage.Progress。延伸阅读迁移到 Nuke 14 之前的版本升级路线Nuke 13 Migration Guide、Nuke 12 Migration Guide新增的动画解析与播放能力AnimatedImages.mdSwiftUI 集成swiftui.mdUIKit 集成uikit.md核心实现源码ImagePipeline.swift、ImageContainer.swift、ImageViewExtensions.swift、TaskQueue.swift赞分享移动开发图像处理【免费下载链接】NukeImage loading system项目地址https://gitcode.com/gh_mirrors/nu/Nuke点击查看免费下载相关推荐Nuke 10 迁移指南从 Nuke 9.x 平滑升级 Image Loading System 的完整实战手册Nuke 10 迁移指南从 Nuke 9.x 平滑升级 Image Loading System 的完整实战手册 本文以 Nuke 官方 Nuke 10 Mi移动开发图像处理Nuke 7 迁移指南从 Nuke 6.x 平滑升级到 ImagePipeline 时代的完整实操手册Nuke 7 迁移指南从 Nuke 6.x 平滑升级到 ImagePipeline 时代的完整实操手册 Nuke 7 是 Nuke 图片加载框架本仓库 So移动开发图像处理Nuke 4 迁移指南从 Nuke 3.x 升级到 Swift 3 时代的架构重构实践Nuke 4 迁移指南从 Nuke 3.x 升级到 Swift 3 时代的架构重构实践 本文是 Nuke 图片加载框架 4.x 版本的官方迁移指南系统梳理了移动开发图像处理上一篇魔兽争霸3终极兼容性解决方案5分钟上手WarcraftHelper插件下一篇为什么Terraformer值得关注告别3大痛点搞定代码漂移与无主遗留基础设施创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表