XUI 是一个工具箱,用于使用 SwiftUI 创建模块化、可重用、可测试的应用程序架构。通过扩展来解决常见问题,XUI 使使用 SwiftUI 和 Combine 变得更加容易!
在我们的博客文章中
我们已经了解了如何在 SwiftUI 中组织视图和视图模型。 凭借所有这些知识,我们已在此库中组合和总结了最重要和最有用的组件。
@Store
属性包装器,使用协议抽象视图模型XUI 的组成部分之一是 Store
属性包装器。 它使得可以使用协议定义 SwiftUI 视图模型。
让我引导你完成这个过程:首先,我们为我们的视图模型创建一个协议,并使其符合 ViewModel
。
import XUI
protocol MyViewModel: ViewModel {
// You can specify properties and methods as you like
// This is just an example
var text: String { get set }
func open()
}
其次,我们为该协议创建一个实现。 我们的实现需要是一个符合 ObservableObject
和我们的协议的类。
import XUI
class DefaultMyViewModel: MyViewModel, ObservableObject {
@Published var text: String
func open() {
// ...
}
}
最后但并非最不重要的一点,我们使用 Store
属性包装器在我们的视图中使用协议作为视图模型。
import XUI
struct MyView: View {
@Store var viewModel: MyViewModel
var body: some View {
TextField("Text", text: $viewModel.text)
}
}
正如你所看到的,你可以像在 SwiftUI 中使用 @ObservedObject
属性包装器一样使用你的视图模型。 你可以指定一个协议而不是被限制为具体的类型。 这样,我们可以编写 MyViewModel
协议的不同实现,并在 MyView
中使用它们。
对于深度链接,我们在你的视图模型/协调器层级结构中提供了一个搜索算法。 你可以使用 DeepLinkable
协议来提供对你的直接子级的访问。 要在该层级结构中查找特定的子级,你可以使用 DeepLinkable
上的 firstReceiver
方法。
你可以在这篇博客文章中找到更详细的解释。
XUI 使使用 Combine 和 SwiftUI 更加容易!
当广泛使用 Combine 时,你的代码中可能会出现很多 .store(in: &cancellables)
。 为了最大限度地减少代码大小并使代码更具可读性,我们提供了一个函数构建器,可以一次性在集合中插入多个 Cancellables
。 让我们看看它的实际应用
var cancellables = Set<AnyCancellable>()
cancellables.insert {
$myViewModel.title
.sink { print("MyViewModel title changed to", $0) }
$myViewModel.text
.sink { print("MyViewModel text changed to", $0) }
}
对于 Publishers,你通常使用 singles 或者简单的 publishers,它们只会发出单个值或错误。 为了使使用这些 publishers 更容易(并且由于 Result
类型现在是 Swift 的一部分),我们可以简单地构建以下扩展
var publisher: AnyPublisher<String, MyError>
publisher.asResult() // AnyPublisher<Result<String, MyError>, Never>
publisher.mapResult(success: { $0 }, failure: { _ in "Error occured." }) // AnyPublisher<String, Never>
publisher.tryMapResult(success: { $0 }, failure: { throw $0 }) // AnyPublisher<String, Error>
当在 SwiftUI 中使用 Coordinator 模式时(如这篇博客文章中所讨论的),我们需要将视图修饰符注入到子视图中,以便过渡逻辑完全由协调器视图指定,而不是分布在各个视图中。
提供了 NavigationModifier
、PopoverModifier
和 SheetModifier
,它们具有与实际修饰符类似的接口。
为了简化在 SwiftUI 中使用 NavigationView
,我们提供了一个 onNavigation
方法,当你想在执行 NavigationLink
时执行闭包时可以使用该方法。 只需将其放在你的视图周围,它将自行添加 NavigationLink
。
此外,我们为你的视图添加了使用视图模型协议处理 sheet
、popover
和 navigation
的方法。
示例
struct MyView: View {
@Store var viewModel: MyViewModel
var body: some View {
NavigationView {
Text("Example")
.navigation(model: $viewModel.detailViewModel) { viewModel in
DetailView(viewModel: viewModel)
}
.sheet(model: $viewModel.sheetViewModel) { viewModel in
SheetView(viewModel: viewModel)
}
}
}
}
使用 bindings,特别是当它涉及到集合时,是很困难的 - 但现在不再是了! 我们编写了一些扩展,可以轻松地使用 bindings 处理集合的元素。
var binding: Binding<[String]>
binding.first(equalTo: "example") // Binding<String?>
binding.first(where: { $0.count < 5 }) // Binding<String?>, this is not a practical example though
binding.first(equalTo: "example").forceUnwrap() // Binding<String>
binding.first(equalTo: "example").force(as: CustomStringConvertible.self) // Binding<CustomStringConvertible>
此外,人们可能希望更改或观察通过 binding 使用的值。
var binding: Binding<String>
binding.willSet { print("will set", $0) }
// Binding<String>, will print whenever a new value is set by the binding, before it is forwarded to the initial binding
binding.didSet { print("did set", $0) }
// Binding<String>, will print whenever a new value is set by the binding, after it is forwarded to the initial binding
binding.ensure { !$0.isEmpty }
// Binding<String>, will only set the initial binding, when the condition is fulfilled
binding.assert { !$0.isEmpty }
// Binding<String>, will assert on get and set, that a condition is fulfilled
binding.map(get: { $0.first! }, set: { String($0) })
// Binding<String>, will map the binding's value to a different type
binding.alterGet { $0.prefix(1) }
// Binding<String>, will forward the altered value on get
binding.alterSet { $0.prefix(1) }
// Binding<String>, will forward the altered value on set to the underlying binding
作为如何在你的应用程序中使用 XUI 的示例,我们借助 XUI 编写了一个 Recipes App。
有关如何在你的应用程序中使用 Swift 包的更多信息,请参阅 这个 WWDC 演示文稿。 指定 https://github.com/quickbirdstudios/XUI.git
作为 XUI
包链接。
此框架由 QuickBird Studios 用 ❤️ 创建。
如果你需要帮助、发现错误或想要讨论功能请求,请打开一个 issue。 如果你想更改 XUI,请打开一个 PR。
XUI 在 MIT 许可下发布。 有关更多信息,请参阅 License.md。