我正在尝试阅读密钥链,但文档警告我如下:
SecItemCopyMatching阻塞调用线程,因此如果从主线程调用,它会导致应用程序的UI挂起。相反,从后台调度队列或异步函数调用SecItemCopyMatching。
因此,我想编写一个在后台运行的异步方法。
actor Keychain {
public static let standard = Keychain()
public enum Error: Swift.Error {
case failed(String)
}
public func get(_ key: String) async throws -> Data? {
let backgroundTask = Task(priority: .background) {
var query: [String: Any] = [
type(of: self).klass : kSecClassGenericPassword,
type(of: self).attrAccount : key,
type(of: self).matchLimit : kSecMatchLimitOne,
type(of: self).returnData : kCFBooleanTrue as CFBoolean
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else {
if let errorMessage = SecCopyErrorMessageString(status, nil) {
throw Error.failed(String(errorMessage))
} else {
throw Error.failed("unsupported")
}
}
return item as? Data
}
return try await backgroundTask.value
}
}我的问题是。演员会不会已经让线程安全了?
通常,为了安全起见,我会添加一个NSLock。
public func get(_ key: String) async throws -> Data? {
lock.lock()
defer { lock.unlock() }
(...)
return try await task.value
}然而,现在我收到了一个警告Instance method 'lock' is unavailable from asynchronous contexts; Use async-safe scoped locking instead; this is an error in Swift 6。
那么我是如何做到这一点的呢?
发布于 2022-10-26 15:30:35
是的,演员们会让它安全的。不需要锁之类的。参见WWDC 2021视频用斯威夫特演员保护易变状态。
顺便说一句,既然你已经在演员身上看到了这一点,你真的不需要让get(_:)成为一个async方法。演员已经在后台线程上运行。因此,删除async限定符,然后删除Task
actor Keychain {
...
public func get(_ key: String) throws -> Data? {
var query: [String: Any] = [
type(of: self).klass : kSecClassGenericPassword,
type(of: self).attrAccount : key,
type(of: self).matchLimit : kSecMatchLimitOne,
type(of: self).returnData : kCFBooleanTrue as CFBoolean
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else {
if let errorMessage = SecCopyErrorMessageString(status, nil) {
throw Error.failed(String(errorMessage))
} else {
throw Error.failed("unsupported")
}
}
return item as? Data
}
}发布于 2022-10-26 15:36:29
为什么要将密钥链操作放在不需要的异步块中。你不用它就走吧。密钥链操作是线程安全的,这是由苹果公司保证的。请看这份文件。苹果
因此,在不使用异步块的情况下这样做,并将所有ui更改放在主线程中(如果还没有)。UI更改需要在主线程中进行。
https://stackoverflow.com/questions/74210041
复制相似问题