【问题标题】:Memory leak in ABAddressBook iOS 8 in SwiftSwift 中 ABAddressBook iOS 8 中的内存泄漏
【发布时间】:2016-06-09 20:27:37
【问题描述】:

我正在 iOS 8 中实现ABAddressBook,我首先创建了一个示例项目以开始工作。我使用 Single View Application 模板创建了项目。在ViewController.swiftViewControllerviewDidAppear中我添加了以下代码:

if ABAddressBookGetAuthorizationStatus() != .Authorized {
    return
}
var error: Unmanaged<CFError>?
if let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, &error)?.takeRetainedValue() {
    ABAddressBookRequestAccessWithCompletion(addressBook) { granted, error in
        if error == nil && granted {
            if let contacts = ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue() as? NSArray {
                for contact in contacts {
                    print("new contact")
                }
            }
        }
    }
} else {
    print(error?.takeRetainedValue())
}

这是我唯一的代码,应用程序正在泄漏!我正在运行 Leaks 工具,但它没有提供足够好的上下文来说明应用程序泄漏的原因。

泄漏工具快照

调用树快照

泄漏周期快照

我没有发布应该发布的东西吗?我也不能打电话给CFRelease,因为我启用了ARC。

【问题讨论】:

  • 这段代码对我来说看起来不错。如果您不小心在某处使用了takeUnretainedValue,那可能会泄漏,但我在您的代码 sn-p 中看不到任何地方。 iOS 确实有一些这样的小漏洞散布在各处,所以我不会担心它们,除非它很大或者你看到你的任何类都没有被释放。顺便说一句,如果可能,请考虑使用 Contacts 框架,它更易于使用,并且不需要像 AddressBook 框架那样脆弱的takeRetainedValue 调用过程。
  • ABAddressBook 在 iOS 9 中已弃用。您可能会从使用 CNContactStore 中受益。
  • @gjeck 我支持 iOS 8 设备,所以我不能在 iOS 8 设备上使用 CNContactStore。

标签: ios swift memory-leaks abaddressbook


【解决方案1】:

我无法重现,但值得的是,以下内容也没有泄漏:

var addressBook: ABAddressBookRef?

func extractABAddressBookRef(abRef: Unmanaged<ABAddressBookRef>!) -> ABAddressBookRef? {
    if let ab = abRef {
        return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue()
    }
    return nil
}

func fetchAllContacts(completion: ((contacts: [String]?) -> Void)?) {
    let authorizationStatus = ABAddressBookGetAuthorizationStatus()
    switch authorizationStatus {
    case .NotDetermined:
        print("requesting access...")
        var errorRef: Unmanaged<CFError>? = nil
        addressBook = extractABAddressBookRef(ABAddressBookCreateWithOptions(nil, &errorRef))
        ABAddressBookRequestAccessWithCompletion(addressBook, { [weak self] success, error in
            if success {
                completion?(contacts: self?.getContactNames())
            }
            else {
                print("error")
                completion?(contacts: nil)
            }
        })
    case .Denied, .Restricted:
        print("access denied")
        completion?(contacts: nil)
    case .Authorized:
        print("access granted")
        completion?(contacts: self.getContactNames())
    }
}

func getContactNames() -> [String]? {
    var errorRef: Unmanaged<CFError>?
    addressBook = extractABAddressBookRef(ABAddressBookCreateWithOptions(nil, &errorRef))
    let contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()
    print("records in the array \(contactList.count)")

    return contactList.map({ (record: AnyObject) -> String in
        let contactRef: ABRecordRef = record
        let contactName: String = ABRecordCopyCompositeName(contactRef).takeRetainedValue() as String
        return contactName
    })
}

override func viewDidLoad() {
    super.viewDidLoad()

    fetchAllContacts { (contacts) in
        print("fetched contacts \(contacts)")
    }
}

【讨论】:

  • 在获取AddressBookRef 时,您应该使用takeRetainedValue,而不是takeUnretainedValue。您也不需要跳 fromOpaque/toOpaque 舞蹈。 (我们必须在早期的 Swift 测试版中这样做,但现在不是了。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 2020-03-19
  • 2016-02-18
相关资源
最近更新 更多