当遵守协议或重写超类方法时,您可能无法将方法更改为async,但您可能仍然想调用一些async代码。例如,当我正在重写一个根据 Swift 新的结构化并发编写的程序时,我想async通过class func setUp()覆盖XCTestCase. 我希望我的设置代码在任何测试运行之前完成,因此使用Task.detachedorasync { ... }是不合适的。
最初,我写了一个这样的解决方案:
final class MyTests: XCTestCase {
override class func setUp() {
super.setUp()
unsafeWaitFor {
try! await doSomeSetup()
}
}
}
func unsafeWaitFor(_ f: @escaping () async -> ()) {
let sema = DispatchSemaphore(value: 0)
async {
await f()
sema.signal()
}
sema.wait()
}
Run Code Online (Sandbox Code Playgroud)
这似乎运作良好。然而,在《Swift 并发:幕后花絮》中,运行时工程师 Rokhini Prabhu 指出:
信号量和条件变量等基元与 Swift 并发一起使用是不安全的。这是因为它们隐藏了 Swift 运行时的依赖信息,但在代码的执行中引入了依赖关系……这违反了线程前进的运行时契约。
她还包含了这种不安全代码模式的代码片段
func updateDatabase(_ …Run Code Online (Sandbox Code Playgroud) 在 Swift 中,以下代码编译没有问题。
protocol P1 {
associatedtype T = Int
}
protocol P2 {
typealias T = Int
}
Run Code Online (Sandbox Code Playgroud)
对我来说,这些似乎表现得几乎相同。我注意到的唯一区别是对何时可以使用有额外的限制,P1因为它具有关联类型。特别是,let x: P1是一个错误而let x: P2很好。
这两种协议之间的实际区别是什么?它们在编译代码中的处理方式不同吗?最后,使用P1而不是有优势P2吗?
为清楚起见编辑:
我知道关联类型和类型别名之间的工作差异,所以我很惊讶你甚至可以给关联类型一个固定值。这似乎违背了关联类型的全部目的。我想知道是否有任何实用程序可以为关联类型提供固定值,并且我想知道这两个协议在编译后是否不同。
我正在尝试(基本上没有任何理由)制定一个协议来描述类别理论中的类别。我试图想出这样的东西。
protocol Category {
associatedtype Object: Protocol
}
protocol Hom {
associatedtype C: Category
associatedtype Source: C.Object
associatedtype Target: C.Object
}
Run Code Online (Sandbox Code Playgroud)
特别是,我希望每个 Hom 类型都有一个关联的类别 C 以及关联的源和目标类型,它们都是该类别中的对象。因此,我将一个对象协议与每个类别相关联,并尝试使 Hom 的源和目标符合相应类别的对象协议。上面的代码无法编译
Type 'Self.Source' constrained to non-protocol, non-class type 'Self.C.Object'
Run Code Online (Sandbox Code Playgroud)
这个错误至少不清楚,因为 C.Object 被声明为协议。有什么办法可以解决这个问题吗?
编辑:
正如 Rob 所指出的,代码本身没有多大意义。Protocol 是 ObjC 中的一个特定类,而不是描述协议的类型。此外,不存在描述所有协议的类型,因为协议本身不能符合协议,因为它们只是对其他类型的要求。我正在寻找的是一个元类型,其中 Any.Protocol、Sequence.Protocol 等都是其实例。
我将更详细地说明我试图描述哪种结构。
类别是一个对象类型以及每对对象实例之间的同态类型。对于 Object 的两个实例 A 和 B,同态类型通常写为 Hom(A,B),但我会写Hom<A,B>为 Swiftier。然后类别配备有带有签名的组合<A: Object, B: Object, C: Object>(_ f: Hom<A,B>, _ g: Hom<B,C>) -> Hom<A,C>。
如果 f 是 的实例Hom<A,B>,则 A …
我正在 Swift 中开发一个命令行应用程序,它将调用来swift初始化包、编译东西、测试东西等。我正在使用 swift 包管理器和 Xcode。在我的工具中,我swift从Process. 如果我从命令行运行我的工具,那么效果很好。但是,如果我从 Xcode 运行我的工具,一些奇怪的事情会打印到标准错误中。特别是,我得到
Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift for reading: Too many levels of symbolic links
Run Code Online (Sandbox Code Playgroud)
是什么原因造成的?有什么方法可以避免它,或者我可以不从 Xcode 运行/测试这个实用程序吗?
以下是重现步骤:
mkdir XcodeRedirectionTest
cd XcodeRedirectionTest
swift package init
open Package.swift
Run Code Online (Sandbox Code Playgroud)
然后在 中Tests/XcodeRedirectionTestTests/XcodeRedirectionTestTests.swift,粘贴
Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift for reading: Too many levels of symbolic links
Run Code Online (Sandbox Code Playgroud)
在 Xcode 中测试失败并显示
file://.../XcodeRedirectionTest/Tests/XcodeRedirectionTestTests/XcodeRedirectionTestTests.swift: test failure: XcodeRedirectionTestTests.testExample() failed: XCTAssertEqual failed: ("2021-05-18 19:43:18.084463-0400 swift[2836:4100702] Failed to open macho file …Run Code Online (Sandbox Code Playgroud) 有时在 Swift 中,为委托JSONDecoder或工厂方法的类编写初始化程序可能会很方便。例如,一个人可能想写
final class Test: Codable {
let foo: Int
init(foo: Int) {
self.foo = foo
}
func jsonData() throws -> Data {
try JSONEncoder().encode(self)
}
convenience init(fromJSON data: Data) throws {
self = try JSONDecoder().decode(Self.self, from: data)
}
}
let test = Test(foo: 42)
let data = try test.jsonData()
let decodedTest = try Test(fromJSON: data)
print(decodedTest.foo)
Run Code Online (Sandbox Code Playgroud)
但这无法编译
Cannot assign to value: 'self' is immutable.
Run Code Online (Sandbox Code Playgroud)
解决此问题的解决方案是什么?