Compatibility 是一组旨在提高兼容性的代码,以便在旧平台上使用现代 API,并为某些操作提供简化的语法。还包括 Debug 模块和 Test harness 模块。Debug 是一组旨在轻松编写和启用/禁用代码中的调试语句的代码。这允许轻松地仅中断某些级别的语句,并在输出中具有一致的标志,以便于阅读调试输出。还包括 Int 上的兼容性函数。
主要目标是易于多人维护,采用可在所有平台上使用的一致 API,以及可以使用 iPad 和 macOS 上的 Swift Playgrounds 进行维护。API 通常即使在不支持所有功能的平台上也存在,因此不必在外部代码中执行可用性检查,并且在不相关的情况下,代码可以简单地返回可选值。
这是积极维护的项目,因此如果有功能请求或更改,我们将力争在一周内解决。
main {}
和 background {}
)。.DEBUG
和 .NOTICE
级别的语句将仅在 DEBUG 构建配置期间输出,并且在为 RELEASE 构建配置编译时不会输出。请参阅 CHANGELOG.md 以了解已知问题和路线图 请注意,DataStore 测试仅在包含 entitlements 和 privacyinfo 时才有效(因此,它们在 Previews 和 Swift Playgrounds 中将不起作用)。
通过将其作为包依赖项添加到您的代码中进行安装。这可以在 Xcode 或 Swift Playgrounds 中完成!
您可以通过添加包在 Swift Playground 中尝试这些示例:https://github.com/kudit/Compatibility
如果存储库是私有的,请使用以下链接导入:https://<your-PAT-string>@github.com/kudit/Compatibility.git
或者您可以手动在 Package.swift 文件中输入以下内容
dependencies: [
.package(url: "https://github.com/kudit/Compatibility.git", from: "1.0.0"),
]
首先确保导入框架
import Compatibility
以下是一些用法示例。
let version = Compatibility.version
debug("This is a test string \(true ? "with" : "without") interpolation")
debug("Fatal error! This will be output to console typically even in production code.", level: .ERROR)
如果您有只想在调试中显示的功能,可以添加以下内容
if Application.isDebug {
// execute test/debug-only code. This will only run in DEBUG configurations and will be removed during RELEASE compilations.
}
background {
// run long-running code on background thread
sleep(4) // wait for 4 seconds before continuing
delay(0.4) { // run this code after 0.4 seconds (similar to calling await sleep() and then executing code)
main {
// run this code back on the main thread
}
}
}
默认为 true,因此应用程序需要在 init/启动期间调用函数
if false { // this will generate a warning if left as false
debug("This should be run in init.")
}
这应在 App init 中运行。
init() {
Application.track() // ensures Application.main.isFirstRun and Application.main.versions variables are properly set.
if Application.main.isFirstRun {
debug("First Run!")
}
debug("All versions run: \(Application.main.versionsRun)")
}
这非常有用,因此我们不必担心用户是否启用了 iCloud 或他们注销时会发生什么。但是,这将使用 iCloud 或 UserDefaults。切换时,它不会尝试合并或迁移两者之间的数据。请注意,即使您不使用 iCloud,您也需要包含 entitlements 文件,否则这将尝试使用 iCloud 存储,但如果用户登录到 iCloud,则无法保存。应用程序应自动执行正确的操作,并将使用每个键的最后更新值来解决冲突。如果您需要更精细的控制,请缓存该值并监视更改以更新缓存的值。如果您使用此功能,则需要添加 entitlement,因为这使用了 iCloud 键值存储。示例 entitlement 文件可以在 Compatibility.swiftpm/Development/Resources/Entitlements.entitlements
中找到。如果您使用与开发 Xcode 项目类似的结构,您将需要将 Code Signing Entitlements
构建设置设置为 Resources/Entitlements.entitlements
。如果您有 watchOS 应用程序,您可能需要手动设置密钥,而不是从标识符中拉取,以便 watchOS 应用程序和 iOS 应用程序使用相同的存储:例如:$(TeamIdentifierPrefix)com.kudit.CompatibilityTest
(请注意,com
之前没有句点)如果您希望它自动设置并且没有 watchOS 应用程序,请将 iCloud Key-Value Store
entitlement 条目设置为:$(TeamIdentifierPrefix)$(CFBundleIdentifier)
此功能需要 iOS 13、tvOS 13 和 watchOS 9 才能使用云,因为这是 NSUbiquitousKeyValueStore 的最低要求。如果代码使用旧版本,您将需要添加 PrivacyInfo 文件,因为 UserDefaults 可用于指纹识别。示例文件可以在包中的 Compatibility.swiftpm/Development/Resources/PrivacyInfo.xcprivacy
中找到
// either specify a default value or make it an optional
@CloudStorage("keyString") var myKey: Bool = false
@CloudStorage("key2String") var myOtherKey: Double?
// check that existing value exists in UserDefaults and that this value hasn't already been migrated.
if let existingString1 = UserDefaults.standard.object(forKey: .string1Key) as? String, !string1.contains(existingString1) { // legacy support
debug("Migrating local string1: \(existingString1) to cloud string1: \(string1)", level: .NOTICE)
string1 = "\(existingString1),\(string1)"
// zero out local version so we don't do this again in the future. If we log out of iCloud, we will lose the data but that is expected behavior.
UserDefaults.standard.removeObject(forKey: .string1Key)
}
public protocol CustomProtocol {
init(string: String)
var stringValue: String { get }
}
@available(iOS 13, tvOS 13, watchOS 6, *)
extension CloudStorage where Value: CustomProtocol {
public init(wrappedValue: Value, _ key: String) {
self.init(
keyName: key,
syncGet: { CloudStorageSync.shared.string(for: key).flatMap(Value.init) ?? wrappedValue },
syncSet: { newValue in CloudStorageSync.shared.set(newValue.stringValue, for: key) })
}
}
所有这些测试都可以使用预览或通过运行模块 Development 文件夹中捆绑的应用程序可执行文件来演示。
如果您需要实现特定功能或遇到错误,请打开一个 issue。如果您自己扩展了功能并希望其他人也使用它,请提交 pull request。
这花费了很多精力。如果您发现这很有用,特别是如果您在商业产品中使用它,请考虑捐赠至 http://paypal.me/kudit
欢迎在项目中使用此代码,但是,请在应用程序的某处包含指向此项目的链接并注明出处。版本示例 Markdown 和字符串插值
Text("Open Source projects used include [Compatibility](https://github.com/kudit/Compatibility) v\(Compatibility.version)
贡献此项目的完整人员列表可在此处找到:此处。非常感谢所有做出贡献的人!🙏 特别感谢此项目提供的 CloudStorage 基础(此处已清理以获得更广泛的兼容性):https://github.com/nonstrict-hq/CloudStorage