跳到主要内容

SwiftUI 中实现共享跨平台(iOS/macOS)代码

· 阅读需 3 分钟
GoSwiftUI
goswiftui.com

在SwiftUI中构建应用程序的主要吸引力在于能够跨平台共享 UI 代码,尤其是 iOS 和 macOS。它并不完美,您经常需要进行一些#if os()检查,但是当它起作用时,它确实很棒。在 SwiftUI 出现之前,您已经可以在 iOS 和 macOS 之间共享大量(非 UI)代码。许多系统框架在两个平台上都可用,例如FoundationCore Data。偶尔会存在 API 差异,但它们很少会带来很大的负担。

在开发跨平台 SwiftUI 应用程序时,最大的问题是当您需要在 macOS上使用AppKit和在 iOS上使用UIKit时。通常,您需要的 API(因为 SwiftUI 中没有它们)完全不同。但是,有时 API几乎相同,但只是不同,以至于需要分支到特定于平台的代码路径。一个很好的例子是UIPasteboard在 iOS 和NSPasteboardmacOS 上。

在我正在开发的这个跨平台 SwiftUI 应用程序中,我希望允许用户从表格视图中复制一些文本。两个平台共享 UI 代码,但不共享底层复制功能——因为我们需要在 macOS 上使用 AppKit,在 iOS 上使用 UIKit。但我想保持调用站点的复制操作代码干净,无需进行大量#if os()检查。为此,您可以巧妙地使用typealias.

首先,我们在两个平台上定义一个公用的 typealias

#if os(macOS)
import AppKit
typealias XPasteboard = NSPasteboard
#else
import UIKit
typealias XPasteboard = UIPasteboard
#endif

然后我们可以写一个扩展XPasteboard来封装通用功能。

extension XPasteboard {
func copyText(_ text: String) {
#if os(macOS)
self.clearContents()
self.setString(text, forType: .string)
#else
self.string = text
#endif
}
}

我们现在有一个单一的“跨平台”API 可供使用,我喜欢这样使代码更简洁。

XPasteboard.general.copyText(someText)

这只是一个小例子,说明如何解决 AppKit 和 UIKit 中的差异以生成更好的代码,但是当您在两个框架中遇到相似但不同的 API 时,还有很多其他改进的机会。随着您的 SwiftUI 应用程序变得越来越复杂,您将越来越需要 AppKit 和 UIKit。这是我喜欢用来封装一些复杂性的一种策略。