SDWebImageSwiftUI 3.1.1

SDWebImageSwiftUI 3.1.1

维护者:DreamPiggy.



  • DreamPiggy

SDWebImageSwiftUI

CI Status Version License Platform Carthage compatible SwiftPM compatible codecov

如果您只支持 iOS 15+/macOS 12+,且不介意动画图片格式,可以尝试 SwiftUI 的 AsyncImage

用途

SDWebImageSwiftUI 是一个基于 SDWebImage 的 SwiftUI 图片加载框架。

它提供了 SDWebImage 的所有您喜欢的功能,如异步图片加载、内存/磁盘缓存、动画图片播放和性能。

该框架提供了不同的 View 结构,其 API 符合 SwiftUI 框架指导原则。如果您熟悉 Image,您会发现使用 WebImageAnimatedImage 很容易。

特性

由于 SDWebImageSwiftUI 是在 SDWebImage 之上构建的,它既提供了一键化的功能,也提供了您在实际应用程序中可能需要的强大先进的功能。当您需要时,请查看我们的 Wiki

  • 动画图像全栈解决方案,CPU 和 RAM 的平衡
  • 渐进式图像加载,支持动画
  • 可重用下载,永远不要重复请求单个 URL
  • URL 请求/响应修饰符,提供自定义 HTTP 头
  • 图像转换器,应用圆角或 CIFilter
  • 多缓存系统,从不同的来源查询
  • 多加载器系统,从不同资源加载数据

您还可以通过SDWebImage获得现有社区的全部优势。您可以通过Coder插件获得对大量图像格式的支持(GIF/APNG/WebP/HEIF/AVIF/SVG/PDF),通过SDWebImagePhotosPlugin获得PhotoKit支持,通过FirebaseUI进行Firebase集成等。

除了所有这些功能,我们还对SwiftUI进行了优化,例如使用绑定、视图修饰符,采用与SwiftUI兼容的设计模式。

版本

此框架处于高度开发状态,建议尽可能使用最新版本(包括SDWebImage依赖项)。

此框架遵循语义版本控制。每次源代码变更都会提升到主版本号。

变更日志

此项目使用keep-a-changelog格式记录更改。请查看CHANGELOG.md以了解版本之间的更改。这些更改也将更新在发布页面。

合作

所有问题报告、功能请求、贡献和GitHub星星都受欢迎。如果您发现此框架有用,希望获得积极的反馈和推广。

需求

  • Xcode 12+
  • iOS 13+(推荐 14+)
  • macOS 10.15+(推荐 11+)
  • tvOS 13+(推荐 14+)
  • watchOS 6+(推荐 7+)

SwiftUI 2.0 兼容性

iOS 14(macOS 11)推出了 SwiftUI 2.0,保持了最大的 API 兼容性,但改变了许多内部行为,这使得 SDWebImageSwiftUI 的功能发生了破坏。

从 v2.0.0 版本开始,我们采用了 SwiftUI 2.0 和 iOS 14(macOS 11)的行为。你可以在新的 LazyVStack 中使用 WebImageAnimatedImage

var body: some View {
    ScrollView {
        LazyVStack {
            ForEach(urls, id: \.self) { url in
                AnimatedImage(url: url)
            }
        }
    }
}

注意:然而,iOS 13/14 之间有许多行为差异难以修复。我们可能为了修复它而破坏一些 API(这些 API 并未设计为公开 API)。

由于维护问题,在未来的版本中,我们将放弃对 iOS 13 的支持,并始终匹配 SwiftUI 2.0 的行为。而且 v2.x 可能是支持 iOS 13 的最后一个版本。

安装

Swift Package Manager

SDWebImageSwiftUI 可通过 Swift Package Manager 获取。

  • 对于应用程序集成

为了App集成,您应使用Xcode 12或更高版本,将此包添加到您的App目标中。为此,请检查将包依赖项添加到您的应用程序的指南,了解使用Xcode的逐步教程。

  • 对于下游框架

对于下游框架的作者,您应在您的git仓库中创建一个Package.swift文件,然后添加以下行,以标记您的框架依赖于SDWebImageSwiftUI。

let package = Package(
    dependencies: [
        .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0")
    ],
)

CocoaPods

SDWebImageSwiftUI可以通过CocoaPods获取。要安装它,只需将以下行添加到您的Podfile中

pod 'SDWebImageSwiftUI'

Carthage

SDWebImageSwiftUI可以通过Carthage获取。

github "SDWebImage/SDWebImageSwiftUI"

使用

WebImage加载网络图片

  • 支持占位符和详细选项来控制图片加载,与SDWebImage相同
  • 支持渐进式图片加载(类似于baselined)
  • 支持成功/失败/进度变化事件,用于自定义处理
  • 支持带有活动/进度指示器和自定义的indicator
  • 支持内置动画和过渡,由SwiftUI提供支持
  • 也支持动画图!
var body: some View {
    WebImage(url: URL(string: "https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic"))
    // Supports options and context, like `.delayPlaceholder` to show placeholder only when error
    .onSuccess { image, data, cacheType in
        // Success
        // Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data
    }
    .resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
    .placeholder(Image(systemName: "photo")) // Placeholder Image
    // Supports ViewBuilder as well
    .placeholder {
        Rectangle().foregroundColor(.gray)
    }
    .indicator(.activity) // Activity Indicator
    .transition(.fade(duration: 0.5)) // Fade Transition with duration
    .scaledToFit()
    .frame(width: 300, height: 300, alignment: .center)
}

说明:这个 WebImage 在内部实现时使用 Image,这是与 SwiftUI 布局和动画系统最兼容的。但是,与 SwiftUI 的 Image 不支持动画图像或矢量图像不同,WebImage 支持(自 v2.0.0 版起默认支持)动画图像。

但是,WebImage 的动画提供了简单的常用功能,因此我们仍然推荐使用 AnimatedImage 进行高级操作,如渐进式动画渲染或矢量图像渲染。

@State var isAnimating: Bool = true
var body: some View {
    WebImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), isAnimating: $isAnimating)) // Animation Control, supports dynamic changes
    // The initial value of binding should be true
    .customLoopCount(1) // Custom loop count
    .playbackRate(2.0) // Playback speed rate
    .playbackMode(.bounce) // Playback normally to the end, then reversely back to the start
    // `WebImage` supports advanced control just like `AnimatedImage`, but without the progressive animation support
}

说明:对于指示器,你也可以自定义。例如,iOS 14 和 watchOS 7 引入了新的 ProgressView,可以替换我们内置的 ProgressIndicator/ActivityIndicator(在 watchOS 中不提供)。

WebImage(url: url)
.indicator {
    Indicator { _, _ in
        ProgressView()
    }
}

使用 AnimatedImage 播放动画

  • 支持网络图像以及本地数据和包图像
  • 支持动态图像格式及矢量图像格式
  • 支持类似网络浏览器的动态渐进图像加载
  • 支持使用 SwiftUI Binding 控制动画
  • 支持由 SDWebImage 和 Core Animation 提供的指示器和过渡效果
  • 支持高级控制,如循环次数、播放速率、缓冲区大小、runloop 模式等
  • 支持与原生 UIKit/AppKit 视图的坐标对齐
var body: some View {
    Group {
        AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
        // Supports options and context, like `.progressiveLoad` for progressive animation loading
        .onFailure { error in
            // Error
        }
        .resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
        .placeholder(UIImage(systemName: "photo")) // Placeholder Image
        // Supports ViewBuilder as well
        .placeholder {
            Circle().foregroundColor(.gray)
        }
        .indicator(SDWebImageActivityIndicator.medium) // Activity Indicator
        .transition(.fade) // Fade Transition
        .scaledToFit() // Attention to call it on AnimatedImage, but not `some View` after View Modifier (Swift Protocol Extension method is static dispatched)
        
        // Data
        AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
        .customLoopCount(1) // Custom loop count
        .playbackRate(2.0) // Playback speed rate
        
        // Bundle (not Asset Catalog)
        AnimatedImage(name: "animation1.gif", isAnimating: $isAnimating) // Animation control binding
        .maxBufferSize(.max)
        .onViewUpdate { view, context in // Advanced native view coordinate
            // AppKit tooltip for mouse hover
            view.toolTip = "Mouseover Tip"
            // UIKit advanced content mode
            view.contentMode = .topLeft
            // Coordinator, used for Cocoa Binding or Delegate method
            let coordinator = context.coordinator
        }
    }
}

说明:AnimatedImage 支持动画图像格式的图像 URL 或图像数据。它使用 SDWebImage 的 Animated ImageView 作为内部实现。请注意,由于这基于 UIKit/AppKit 可表示的,一些高级 SwiftUI 布局和动画系统可能无法按预期工作。你可能需要使用 UIKit/AppKit 和 Core Animation 来修改原生视图。

说明:AnimatedImage 的一些方法,如 .transition.indicator.aspectRatio,与 SwiftUI.View 协议方法的命名相同。但接收不同类型的参数。这是因为在 AnimatedImage 中,可以将其与 UIKit/AppKit 组件和动画一起使用。如果你发现存在歧义,请使用完整的类型声明而不是点表达式语法。

说明:AnimatedImage 上的一些方法将返回 some View,一种新的修改后的内容。这会导致你失去与类型相关的修改方法。在这种情况下,你可以重新排列方法调用,或在 .onViewUpdate 中使用 Native View 来进行挽救。

// Using UIKit components
var body: some View {
    AnimatedImage(name: "animation2.gif") 
    .indicator(SDWebImageProgressIndicator.default) // UIKit indicator component
    .transition(SDWebImageTransition.flipFromLeft) // UIKit animation transition
}

// Using SwiftUI components
var body: some View {
    AnimatedImage(name: "animation2.gif")
    .indicator(Indicator.progress) // SwiftUI indicator component
    .transition(AnyTransition.flipFromLeft) // SwiftUI animation transition
}

选择哪个视图

为什么这里有两种不同的视图类型,是因为当前 SwiftUI 的限制。但我们旨在为所有用例提供最佳解决方案。

如果你不需要动画图像,首先选择使用 WebImage。它的表现与内置的 SwiftUI 视图几乎无缝。如果 SwiftUI 行得通,它就有效。如果 SwiftUI 不行,就照此进行。

如果您需要简单的动画图片,请使用WebImage。它提供基本的动画图片支持。但是,它不支持渐进式动画渲染和矢量图,如果您不关心这一点。

如果您需要强大的动画图片,选择AnimatedImage。请记住,它也支持静态图片,您无需检查格式,直接使用即可。此外,一些强大的功能,如UIKit/AppKit着色颜色、矢量图、符号图配置、tvOS分层图像,仅在AnimatedImage中可用,不在SwfitUI中。

但是,由于AnimatedImage使用UIViewRepresentable并由UIKit驱动,目前 UIKit和SwiftUI的布局和动画系统之间可能存在一些小的兼容性问题,或者与SwiftUI本身相关的错误。我们尽力匹配SwiftUI的行为,并提供与WebImage相同的API,这样在需要时可以轻松地在这两种类型之间切换。

为您的自定义View类型使用ImageManager

ImageManager是一个符合Combine's ObservableObject协议的类。它是我们提供的WebImage的核心数据源。

对于高级用例,例如,在不需要使用WebImage的复杂View图形中加载图片,您可以直接使用自己的View类型与Manager绑定。

它与SDWebImageManager类似,但为SwiftUI世界构建,提供加载图片的真相来源。您最好使用SwiftUI的@ObservedObject绑定每个Manager实例到您的View实例,这样当图片状态改变时,会自动更新您的View的主体。

struct MyView : View {
    @ObservedObject var imageManager = ImageManager()
    var body: some View {
        // Your custom complicated view graph
        Group {
            if imageManager.image != nil {
                Image(uiImage: imageManager.image!)
            } else {
                Rectangle().fill(Color.gray)
            }
        }
        // Trigger image loading when appear
        .onAppear { self.imageManager.load(url: url) }
        // Cancel image loading when disappear
        .onDisappear { self.imageManager.cancel() }
    }
}

自定义和配置设置

这个框架基于SDWebImage,支持高级自定义和配置,以满足不同用户的需要。

您可以注册多个用于外部图像格式的编码器插件。您可以注册多个缓存(不同的路径和配置)、多个加载器(URLSession和Photos URLs)。您可以控制缓存的过期日期、大小、下载优先级等。所有这些都在我们的wiki中。

为SwiftUI应用放置这些设置代码的最佳位置是AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Add WebP/SVG/PDF support
    SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
    SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
    SDImageCodersManager.shared.addCoder(SDImagePDFCoder.shared)
    
    // Add default HTTP header
    SDWebImageDownloader.shared.setValue("image/webp,image/apng,image/*,*/*;q=0.8", forHTTPHeaderField: "Accept")
    
    // Add multiple caches
    let cache = SDImageCache(namespace: "tiny")
    cache.config.maxMemoryCost = 100 * 1024 * 1024 // 100MB memory
    cache.config.maxDiskSize = 50 * 1024 * 1024 // 50MB disk
    SDImageCachesManager.shared.addCache(cache)
    SDWebImageManager.defaultImageCache = SDImageCachesManager.shared
    
    // Add multiple loaders with Photos Asset support
    SDImageLoadersManager.shared.addLoader(SDImagePhotosLoader.shared)
    SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared
    return true
}

更多信息,建议查看我们的示例,了解API详细使用。您还可以查看最新的API文档,以了解高级使用。

文档

常见问题

常见问题

在 List/LazyStack/LazyGrid 和 ForEach 中使用 WebImage/AnimatedImage

SwiftUI 在使用 List/LazyStack/LazyGrid 中的有已知行为(问题?)。只有 顶层 视图可以持有其自己的 @State/@StateObject,但是子结构在滚动出屏幕时会丢失状态。然而,WebImage/Animated 都是状态性的。为了确保即使在滚动出屏幕时也能保持状态的一致性,您可能需要使用一些技巧。

更多信息:见:https://twitter.com/fatbobman/status/1572507700436807683?s=21&t=z4FkAWTMvjsgL-wKdJGreQ

简而言之,不建议这样做

struct ContentView {
    @State var imageURLs: [String]
    var body: some View {
        List {
            ForEach(imageURLs, id: \.self) { url in
                VStack {
                    WebImage(url) // The top level is `VStack`
                }
            }
        }
    }
}

相反,使用这种方法

struct ContentView {
    struct BodyView {
        @State var url: String
        var body: some View {
            VStack {
                WebImage(url)
            }
        }
    }
    @State var imageURLs: [String]
    var body: some View {
        List {
            ForEach(imageURLs, id: \.self) { url in
                BodyView(url: url)
            }
        }
    }
}

在按钮/导航链接中使用 Image/WebImage/AnimatedImage

SwiftUI 的 Button 默认对其内容(除了 Text)应用叠加层,编写如下代码是一种常见的错误,会导致奇怪的行怍

// Wrong
Button(action: {
    // Clicked
}) {
    WebImage(url: url)
}
// NavigationLink create Button implicitly
NavigationView {
    NavigationLink(destination: Text("Detail view here")) {
        WebImage(url: url)
    }
}

相反,您必须覆盖 .buttonStyle 以使用纯样式,或使用 .renderingMode 使用原始模式。您还可以使用 .onTapGesture 修饰符进行触摸处理。请参阅 如何在 Button 和 NavigationLink 中的图像禁用叠加颜色

// Correct
Button(action: {
    // Clicked
}) {
    WebImage(url: url)
}
.buttonStyle(PlainButtonStyle())
// Or
NavigationView {
    NavigationLink(destination: Text("Detail view here")) {
        WebImage(url: url)
        .renderingMode(.original)
    }
}

与外部加载器/缓存/编码器一起使用

SDWebImage 本身支持许多自定义加载器(例如 Firebase StoragePhotosKit)、缓存(例如 YYCachePINCache),以及编码器(例如 WebPAVIF,甚至 Lottie)。

这是如何使用 SwiftUI 环境设置这些外部组件的教程。

设置外部 SDK

您可以将设置代码放在您的 SwiftUI App.init() 方法内部。

@main
struct MyApp: App {
    
    init() {
        // Custom Firebase Storage Loader
        FirebaseApp.configure()
        SDImageLoadersManager.shared.loaders = [FirebaseUI.StorageImageLoader.shared]
        SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared
        // WebP support
        SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

或者,如果您的 App 具有复杂的 AppDelegate 类,可以将设置代码放在那里

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        SDImageCachesManager.shared.caches = [YYCache(name: "default")]
        SDWebImageManager.defaultImageCache = SDImageCachesManager.shared
        return true
    }
}

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
使用外部SDK

对于某些自定义加载器,您需要使用一些特殊API创建URL结构,以便SDWebImage可以从其他SDK中检索上下文,例如

  • FirebaseStorage
let storageRef: StorageReference
let storageURL = NSURL.sd_URL(with: storageRef) as URL?
// Or via convenience extension
let storageURL = storageRef.sd_URLRepresentation
  • PhotosKit
let asset: PHAsset
let photosURL = NSURL.sd_URL(with: asset) as URL?
// Or via convenience extension
let photosURL = asset.sd_URLRepresentation

对于某些自定义编解码器,您需要使用一些选项请求图像以控制行为,例如矢量图像SVG/PDF。因为SwiftUI.Image或WebImage完全不支持矢量图形。

  • SVG/PDF 编解码器
let vectorURL: URL? // URL to SVG or PDF
WebImage(url: vectorURL, context: [.imageThumbnailPixelSize: CGSize(width: 100, height: 100)])
  • Lottie 编解码器
let lottieURL: URL? // URL to Lottie.json
WebImage(url: lottieURL, isAnimating: $isAnimating)

对于缓存,您实际上不必担心任何事情。设置完成后,它会自动工作。

用于向后部署和弱引用SwiftUI

SDWebImageSwiftUI支持当您的App Target的部署目标版本小于iOS 13/macOS 10.15/tvOS 13/watchOS 6时使用。这允许弱链接SwiftUI(Combine),以便在运行时进行可用性检查编写代码。

要使用向后部署,您必须完成以下操作

添加弱引用框架

-weak_framework SwiftUI -weak_framework Combine添加到您的App Target的Other Linker Flags构建设置中。您也可以使用Xcode的Optional Framework复选框完成此操作,这将产生相同的效果。

请注意,所有第三方SwiftUI框架都应该有此构建设置,而不仅仅是SDWebImageSwiftUI。否则,当在iOS 12设备上运行时,它将在启动时触发运行时dyld错误。

在iOS 12.1上的回退部署-

对于低于iOS 12.2的部署目标版本(Swift 5运行时首次内置到iOS系统中的版本),您必须更改SDWebImageSwiftUI的最小部署目标版本。这可能会对编译器的优化产生一些副作用,并触发某些框架的大量警告。

然而,对于iOS 12.2+,您仍然可以将最小部署目标版本保持为iOS 13,iOS 13客户端不会出现额外警告或性能下降。

因为Swift使用最小部署目标版本来检测是否链接App内打包的Swift运行时,还是系统内建的(/usr/lib/swift/libswiftCore.dylib)。

  • 对于CocoaPods用户,您可以通过安装后处理器在Podfile中更改最小部署目标版本。
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' # version you need
    end
  end
end
  • 对于Carthage用户,您可以使用carthage update --no-build下载依赖项,然后更改Xcode项目的部署目标版本并构建二进制框架。

  • 对于SwiftPM用户,您必须使用本地依赖项(带有Git子模块)来更改部署目标版本。

在iOS 12.2+上的回退部署-
  • 对于Carthage用户,构建的二进制框架将使用库进化来支持回退部署。

  • 对于CocoaPods用户,您可以在Podfile中使用以下命令跳过平台版本验证:

platform :ios, '13.0' # This does not effect your App Target's deployment target version, just a hint for CocoaPods
  • 对于SwiftPM用户,SwiftPM不支持弱链接或库进化,因此如果不更改最小部署目标,它无法部署到iOS 12+用户。
添加可用性注释-

将所有带有可用性注释和运行时检查的SwiftUI代码添加进来,如下所示:

// AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // ...
    if #available(iOS 13, *) {
        window.rootViewController = UIHostingController(rootView: ContentView())
    } else {
        window.rootViewController = ViewController()
    }
    // ...
}

// ViewController.swift
class ViewController: UIViewController {
    var label: UILabel = UILabel()
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(label)
        label.text = "Hello World iOS 12!"
        label.sizeToFit()
        label.center = view.center
    }
}

// ContentView.swift
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
struct ContentView : View {
    var body: some View {
        Group {
            Text("Hello World iOS 13!")
            WebImage(url: URL(string: "https://i.loli.net/2019/09/24/rX2RkVWeGKIuJvc.jpg"))
        }
    }
}

示例

要使用 SwiftUI 运行示例,请按照以下步骤操作

  1. 在根目录下运行 pod install 以安装依赖项。
  2. 打开 SDWebImageSwiftUI.xcworkspace,等待 SwiftPM 下载测试依赖项完成。
  3. 选择 SDWebImageSwiftUIDemo 方案并运行示例应用程序。

由于 SwiftUI 致力于支持所有 Apple 平台,我们的示例也做到了这一点,一个代码库涵盖

  • iOS(iPhone/iPad/Mac Catalyst)
  • macOS
  • tvOS
  • watchOS

示例提示

  1. 使用 Switch(在 macOS 上右键单击/在 watchOS 上强制按压)在 WebImageAnimatedImage 之间切换。
  2. 使用 Reload(在 macOS 上右键单击/在 watchOS 上强制按压)清除缓存。
  3. 使用 Swipe Left(在 tvOS 上的菜单按钮)从列表中删除一个图像 URL。
  4. 捏合手势(在 watchOS 上的数字 crown/在 tvOS 上的播放按钮)可放大详细页面上的图像。
  5. 清除缓存并转到详细页面以查看渐进加载。

测试

SDWebImageSwiftUI 有单元测试来提高代码质量。对于 SwiftUI,苹果没有提供官方的单元测试解决方案。

然而,由于 SwiftUI 是基于状态的和基于属性的布局系统,有一些开源项目提供了解决方案

  • ViewInspector:检查视图的运行时属性值(如 .frame 修饰符、.image 值)。我们使用它来测试 AnimatedImageWebImage。它还允许检查原生 UIView/NSView,我们将其用于测试 ActivityIndicatorProgressIndicator

要运行测试

  1. 在根目录下运行 pod install 以安装依赖项。
  2. 打开 SDWebImageSwiftUI.xcworkspace,等待 SwiftPM 下载测试依赖项完成。
  3. 选择 SDWebImageSwiftUITests 方案并开始测试。

我们已经设置了 CI 管道,每个 PR 都将运行测试用例并将测试报告上传到 codecov

屏幕截图

  • iOS 示例

  • macOS 示例

  • tvOS 示例

  • watchOS 示例

额外说明

除了上述所有内容之外,该项目还可以在Swift平台上为SDWebImage本身确保以下功能可用。

  • SwiftUI兼容性
  • Swift包管理器集成
  • Swift源代码兼容性和Swifty

这意味着,该项目是一个核心用例和下游依赖,它推动SDWebImage本身的未来发展。

作者

DreamPiggy

感谢

许可

SDWebImageSwiftUI遵循MIT许可。更多信息请参阅LICENSE文件。