我正在试图理解如何在没有Sendable的情况下在异步环境中使用Apple类,而不会收到这在Swift 6中不起作用的警告.
Select 的武器是NSExtensionContext
,我需要它来获取已传递到共享扩展中的URL.
这是我的原始代码,它只是从扩展上下文中获取URL.启用新的并发判断后,它会发出警告:
不能从可发送闭包中变异主参与者隔离的属性‘url’;这是SWIFT 6中的错误
class ShareViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fetchURL()
}
private func fetchURL() {
guard let extensionContext = self.extensionContext,
let item = extensionContext.inputItems.first as? NSExtensionItem,
let attachments = item.attachments else { return }
for attachment in attachments {
if attachment.hasItemConformingToTypeIdentifier("public.url") {
attachment.loadItem(forTypeIdentifier: "public.url") { url, error in
guard let url else { return }
self.url = url as? URL <-- WARNING! 不能从可发送闭包中变异主参与者隔离的属性‘url’;这是SWIFT 6中的错误
}
}
}
}
}
我知道这个功能是调用MainActor
,但extensionContext
可以使用在任何演员,这是投诉的原因.
首先,我是否可以将url属性标记为Sendable
,以便可以从任何参与者修改它?
为了try 一些不同的东西,我对其进行了修改,以使用最新的async/await
版extensionContect
.
override func viewDidLoad() {
super.viewDidLoad()
Task {
await fetchURL()
}
}
private func fetchURL() async {
guard let extensionContext = self.extensionContext,
let item = extensionContext.inputItems.first as? NSExtensionItem,
let attachments = item.attachments else { return }
for attachment in attachments {
if let url = try? await attachment.loadItem(forTypeIdentifier: "public.url") as? URL { <-- WARNINGS!
self.url = url
}
}
}
这实际上在同一行上给了我4个警告!
隐式异步调用非隔离函数返回的不可发送类型""Any NSSecureCoding""不能跨越执行元边界
传递不可发送类型的参数"[AnyHasable:Any]?"在主要参与者之外-孤立的环境可能会引发数据竞赛
传递不可发送类型的参数"[AnyHasable:Any]?"在主要参与者之外-孤立的环境可能会引发数据竞赛
将不可发送类型"NSItemProvider"的参数传递到主执行元隔离上下文之外可能会导致数据竞争
让我们试着分离Task,以便它在一个新的参与者上运行:
private func fetchURL() async {
guard let extensionContext = self.extensionContext,
let item = extensionContext.inputItems.first as? NSExtensionItem,
let attachments = item.attachments else { return }
Task.detached {
for attachment in attachments { <-- WARNING! Capture of 'attachments' with non-sendable type '[NSItemProvider]' in a `@Sendable` closure
let attachment = attachment
if let url = try? await attachment.loadItem(forTypeIdentifier: "public.url") as? URL {
await MainActor.run { [weak self] in
self?.url = url
}
}
}
}
}
这里只有一条警告:
在
@Sendable
闭包中捕获不可发送类型为"[NSItemProvider]"的"附件"
最后一次,让我们把一切都放在超然的演员身上.这需要使用await
异步访问extensionContext
:
private func fetchURL() async {
Task.detached { [weak self] in
guard let extensionContext = await self?.extensionContext, <-- WARNING! 不可发送类型‘NSExtensionContext?’在隐式异步访问主执行元隔离属性"extsionContext"时,不能跨越执行元边界
let item = extensionContext.inputItems.first as? NSExtensionItem,
let attachments = item.attachments else { return }
for attachment in attachments {
let attachment = attachment
if let url = try? await attachment.loadItem(forTypeIdentifier: "public.url") as? URL {
await MainActor.run { [weak self] in
self?.url = url
}
}
}
}
}
我们得到的错误是:
不可发送类型‘NSExtensionContext?’在隐式异步访问主执行元隔离属性"extsionContext"时,不能跨越执行元边界
我知道一种清除所有警告的方法:
extension NSExtensionContext: @unchecked Sendable {}
我的问题是,使用@unchecked
似乎就像是告诉编译器忽略其后果.
在@MainActor
上运行的UIViewController
中使用这extensionContext
的正确方式是什么?