Project Icon

swift-dependencies-additions

Swift依赖管理的高级扩展库

swift-dependencies-additions扩展了swift-dependencies库的功能,提供多个高级依赖抽象。它包含Accessibility、Application、BundleInfo等基础抽象,以及AppStorage、CoreData和Notification等实验性高级抽象。库中的API设计一致且易于测试,有助于简化iOS应用的依赖管理。开发者可灵活选择导入单个模块或全部依赖项。

依赖项扩展

这是Point-Free的swift-dependencies库的配套库,提供了更高级别的依赖项。

CI

目录

Dependencies是一个出色的库,它帮助你以类似SwiftUI处理其Environment的方式管理你的依赖项。Dependencies已经自带了许多内置的基础依赖项,如clockuuiddate等。

"Dependencies Additions"旨在扩展这些核心依赖项,并为在Apple平台上开发时常需要的许多额外依赖项提供一致且可测试的实现。

该库目前提供了一些低级别的依赖项,用于与以下内容进行接口:

  • AccessibilityUIAccessibility的抽象;
  • ApplicationUIApplication.shared的抽象;
  • AssertionDependency,用于抽象assert(…)调用,并在测试时将其提升为失败; (从v1.3.0版本开始直接在Dependencies中可用)
  • BundleInfo,应用程序info.plist的抽象;
  • Codable,用于将Codable类型编码/解码为Data
  • Compression,使用Compression框架压缩/解压缩Data
  • DataReader/Writer,用于从URL读取/写入Data(来自David Roman的想法);
  • Logger,暴露一个注重隐私的Logger实例;
  • NotificationCenter
  • PersistentContainer,抽象了CoreData的NSPersistentContainer
  • UserDefaults
  • UserNotificationCenter
  • Path,一个通用的AnyHashable集合,你可以向其中推送和弹出标识符以上下文化你的模型;
  • ProcessInfo
  • DeviceUIDeviceWKInterfaceDeviceDCDevice等)。

它还附带了一些更实验性和更高级别的抽象:

  • AppStorage,提供了一个@Dependency.AppStorage属性包装器,模仿SwiftUI@AppStorage,但可以在你的模型和任何并发上下文中使用。
  • CoreData,尝试为你的CoreData图提供一个安全方便的接口(开发中)。
  • Notification,以类型化和可控的AsyncSequence形式暴露NotificationCenter的通知。
  • SwiftUI的Environment,在你的模型中重新发布SwiftUIEnvironment值。

这些高级依赖项目前都是实验性的,它们的目标名称带有下划线。 如果它们的规模/行为合理,它们最终可能会从Dependencies Additions发展成独立的仓库。

这个库还为"核心"依赖项提供了一些直接扩展,如一些新的日期和随机数生成器,以及一些帮助混合AsyncSequence和Combine的工具。

这个列表是初步的,在接下来的几周内,许多新的依赖项将被添加到这个库中。 如果你需要某个特定的依赖项,请随时开启讨论,这样我们可以找到更好的方式将其与其他依赖项整合。

如何使用Dependencies Additions

这个库提供了许多异构的依赖项。将它们全部捆绑在同一个仓库下有许多好处:

  • 所有依赖项的API都经过统一设计,具有可预测的行为。
  • 有些依赖项太小,不足以justification拥有一个完整的仓库。将它们集中在一起有助于发现。
  • 某些依赖项依赖于其他依赖项,如果每个项目都在独立的仓库中,管理起来会复杂得多。

你可以简单地导入DependenciesAdditions伞形产品,一次性获得所有依赖项的访问权限。 如果你更喜欢更多的控制,由于每个依赖项都被封装在自己的模块中,你可以按需"à la carte"地逐个文件导入你需要的依赖项。

使用Xcode包依赖:

添加swift-dependencies-additions包,并只选择"DependenciesAdditions"产品

使用SwiftPM:

dependencies部分添加:

.package(url: "https://github.com/tgrapperon/swift-dependencies-additions", from: "0.1.0")

在每个需要访问这些依赖项的模块中,添加:

.target(
  name: "MyModule",
  dependencies: [
    .product(name: "DependenciesAdditions", package: "swift-dependencies-additions")
  ]
),

这将提供对所有非下划线依赖项的访问。实验性依赖项需要单独导入。例如:

.product(name: "_AppStorage", package: "swift-dependencies-additions")

依赖项快速浏览

我们在这里介绍一些当前随库提供的依赖项。 如果你对AppStorage或类型化Notification等实验性抽象更感兴趣,你可以直接跳到高级依赖项部分。

Application

UIApplication的抽象,你可以用它来与你的应用实例通信。

例如:

class Model {
  @Dependency(\.application) var application

  func setAlternateIcon(name: String) async throws {
    try await self.application.setAlternateIconName(name)
  }
}

然后,在测试时:

@MainActor 
func testAlternateIconIsSet() async throws -> Void {
  var alternateIconName = LockIsolated("")
  let model = withDependencies {
    $0.application.$setAlternateIcon = { name in
      alternateIconName.withValue { $0 = name }
    }
  } operation: { Model() }
  try await model.setAlternateIcon(name: "blueprint")
  XCTAssertEqual(alternateIconName.value, "blueprint")
} 

Accessibility

UIAccessibility的抽象,你可以用它来监控你的应用实例的无障碍状态。

例如:

class Model {
  @Dependency(\.accessibility.isClosedCaptioningEnabled) var isClosedCaptioningEnabled

  func play() -> Void {
    if self.isClosedCaptioningEnabled {
      self.updateClosedCaptions()
    }
  }
}

BundleInfo

这个简单的依赖项暴露了一个BundleInfo类型,允许简单地检索一些与info.plist相关的字段,如bundleIdentifier或应用的version

例如:

@Dependency(\.bundleInfo.bundleIdentifier) var bundleIdentifier

由于这个值经常用于前缀标识符,将这个值作为依赖项暴露允许你在测试时远程控制它。

Codable

该库暴露了两个依赖项来帮助编码或解码你的Codable类型。

@Dependency(\.encode) var encode
@Dependency(\.decode) var decode

struct Point: Codable {
  var x: Double
  var y: Double
}

let point = Point(x: 12, y: 35)
let encoded = try encode(point) // 一个`Data`值
let decoded = try decode(Point.self, from: encoded) // 一个`Point`值

如你所见,API与JSON或PropertyList编码器和解码器非常相似。

默认情况下,encodedecode产生/消费JSON数据。

Compression

encodedecode类似,该库暴露了两个依赖项来压缩和解压缩Data,使用Apple的Compression框架:

@Dependency(\.compress) var compress
@Dependency(\.decompress) var decompress

let uncompressed = "Lorem ipsum dolor sit amet".data(using: .utf8)!
let compressed = try compress(uncompressed, using: .lzfse)
let decompressed = try decompress(compressed, using: .lzfse)

它们也可以从异步上下文调用,在那里使用更高效的变体:

let compressed = try await compress(uncompressed)
let decompressed = try await decompress(compressed)

默认情况下,compressdecompress使用.zlib算法。

Logger

这个依赖项暴露了一个注重隐私的Logger实例。 @Dependency(.logger) var logger

你可以简单地使用它:

logger.log(level: .info, "User with id: \(userID, privacy: .private) did purchase a smoothie")

你可以使用提供的下标简单地创建一个子系统:

@Dependency(\.logger["Transactions"]) var transactionsLogger

PersistentContainer

一个暴露Core Data NSManagedObjectContextNSPersistentContainer。你可以用它作为更复杂抽象的基础。

@Dependency(\.persistentContainer) var persistentContainer

默认情况下,预览版本是一个内存变体,你可以轻松为SwiftUI预览设置模拟:

var previews: some View {
  let model = withDependencies {
    $0.persistentContainer = .default(inMemory: true).with { context in
      let smoothie = Smoothie(context: context)
      smoothie.flavor = "Banana"
    }
  }
  SmoothieView(model: model)
}

ProcessInfo

ProcessInfo的简单抽象,允许检索系统的低级信息。

@Dependency(\.processInfo.thermalState) var thermalState

if thermalState == .critical {
  self.disableFancyAnimations()
}

因为它是一个依赖项,你可以很容易地测试它,而不必修改你的模型。

UserDefaults

UserDefaults的抽象,你可以从用户偏好中读取和保存。 该库暴露了与SwiftUI的AppStorage相同的类型,因此你可以简单地存储和检索你的数据。

@Dependency(\.userDefaults) var userDefaults

userDefaults.set(true, forKey: "hasUserPassedOnboarding")

只需一行代码,你就可以让你的整个应用程序写入你的应用程序组用户默认值,用于测试的内存版本,甚至是通过iCloud同步用户偏好的NSUbiquitousKeyValueStore。 你还可以尝试使用基于\.userDefaults构建的更强大的_AppStorage依赖,它允许使用类似于SwiftUI的AppStorage的API无缝观察和分配用户首选项(可以与之互操作)。

其他依赖项

还有许多其他可用的依赖项,比如用于显示通知的UserNotifications,用于与UIDeviceWKInterfaceDevice交互的Device,用于上下文化模型树的Path,由Clock(你可以控制)控制的点击DateGenerator等。

当然,这只是开始,在接下来的几周内还会添加许多其他依赖项。 我们强烈认为,依赖项范围越广,你就越会使用它们,你的代码就越容易测试和结构化。

高级依赖项

该库提供了一些实验性的高级依赖项。它们目前是"带下划线的",意味着它们的API尚未最终确定。将来可能会将它们提取到自己的库中。

AppStorage

@Dependency.AppStorage("username") var username: String = "Anonymous"

API遵循SwiftUI的AppStorage,但由@Dependency(\.userDefaults)支持。 它可以在你的模型中运行,并可从异步上下文访问。如果使用相同的key,它可以与SwiftUI自己的AppStorage互操作。 投影值是此用户首选项值的AsyncStream<Value>。可以从任何异步上下文观察它们:

@Dependency.AppStorage("isSoundEnabled") var isSoundEnabled: Bool = false

for await isSoundEnabled in $isSoundEnabled {
  await isSoundEnabled ? audioEngine.start() : audioEngine.stop()
}

Notifications

此依赖项允许将Notification作为类型化的AsyncSequence公开。

extension Notifications {
  /// 发布当前设备电池电量的类型化`Notification`。
  @MainActor
  public var batterLevelDidChange: SystemNotificationOf<Float> {
    .init(UIDevice.batteryLevelDidChangeNotification) { notification in
      @Dependency(\.device.batteryLevel) var level;
      return level
    }
  }
}

然后你可以使用专用属性包装器公开此通知:

@Dependency.Notification(\.batteryLevelDidChange) var batteryLevel

公开的值是表示batteryLevelFloat类型的异步序列:

for await level in batteryLevel {
  if level < 0.2 {
    self.isLowPowerModeEnabled = true
  }
}

SwiftUI Environment

此依赖项将SwiftUI的Environment引入你的模型:

@Dependency.Environment(\.colorScheme) var colorScheme
@Dependency.Environment(\.dismiss) var dismiss

然后,在任何View中,使用.observeEnvironmentAsDependency(\.colorScheme)修饰符将此值冒泡到模型中:

HStack { … }
  .observeEnvironmentAsDependency(\.colorScheme)
  .observeEnvironmentAsDependency(\.dismiss)

在上面的例子中,self.colorSchemeColorScheme?self.dismissActionDismissAction?。两者都是可选的,因为它们的存在取决于View的存在,如果这个视图消失,它们可能会再次变为nil。 你可以通过投影值观察它们的值,投影值是包装值的AsyncSequence

for await colorScheme in self.$colorScheme.compactMap{ $0 }.dropFirst() {
  self.logger.info("ColorScheme did change: \(colorScheme)")
}

Core Data(进行中)

这个依赖项仍在进行中,因为我们想要加强API以避免CoreData常见的陷阱。 但你可以在CoreData案例研究中看到它的一个摘录!

接下来是什么?

这只是开始!还有许多其他依赖项需要实现:SpeechVisionKeyChain等… 目前唯一的规则是它不应该自身需要第三方依赖,并且应该在AppleLinux平台上开箱即用。 如果你想贡献一个依赖项,欢迎在讨论中开启一个主题!

安装

你可以通过将DependenciesAdditions作为包添加到项目中来将其添加到Xcode项目中。

https://github.com/tgrapperon/swift-dependencies-additions

如果你想在SwiftPM项目中使用DependenciesAdditions,只需将其添加到你的Package.swift中即可:

dependencies: [
  .package(url: "https://github.com/tgrapperon/swift-dependencies-additions", from: "1.0.0")
]

许可证

该库根据MIT许可证发布。有关详细信息,请参阅LICENSE。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号