如何使用 Swift 的 Keychain API 而不会造成内存泄漏?

问题描述 投票:0回答:1

在 macOS 的 SwiftUI 应用程序中,我尝试在默认钥匙串中保留密码。对于可以说是笨重的 Core Foundation API,并不缺乏示例代码和包装器。它们本质上都使用相同的模式从钥匙串中检索密码 - 某种程度上像这样:

func getPassword(forService service: String) throws -> String? {
    let query = [
        kSecClass:        kSecClassGenericPassword,
        kSecAttrService:  service,
        kSecMatchLimit:   kSecMatchLimitOne,
        kSecReturnData:   true
    ] as NSDictionary
    var result: CFTypeRef?
    let status = SecItemCopyMatching(query, &result)
    if status == errSecItemNotFound {
        return nil
    }
    if status != errSecSuccess {
        throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
    }
    guard let data = result as? Data else { return nil }
    return String(data: data, encoding: .utf8)
}

上面的代码可以工作,但每次调用时也会泄漏内存。泄漏并未在 Instruments 中显示,但当您循环上述函数时,泄漏会很明显。我想线索就在函数的名称中

SecItemCopyMatching
。它复制结果,但结果不会被释放。

这个问题已被记录在案,例如在苹果论坛这里,但我似乎找不到任何解决方案。

我尝试按照这个答案中建议的方式手动释放内存(针对不同的问题),但这会导致崩溃。

关于如何在 Swift 中正确使用

SecItemCopyMatching
有什么想法吗?

swift macos core-foundation
1个回答
0
投票

仪器中未显示泄漏,但当您循环上面的函数时,泄漏很明显。

如果您在循环中运行它,则很可能需要其中的 autorelease pool 来释放循环中生成的自动释放内存。这通常不是必需的,因为自动释放池将在事件循环结束时自动耗尽。但是,如果您有一个生成大量自动释放对象的内部循环,您可能希望尽快耗尽它。

这通常看起来像:

for x in ... {
    @autoreleasepool {
        thingThatGeneratesAutoreleasedObjects()
    }
}

虽然 SecItemCopyMatching 确实复制值,但它们被 ARC 释放。如果您手动管理内存,则需要添加对 CFRelease 的调用,但这在 ARC(Swift 使用的)下不是必需的。

© www.soinside.com 2019 - 2024. All rights reserved.