【问题标题】:Address Book External Change Callback in Swift (with C Function Pointers?)Swift 中的地址簿外部更改回调(使用 C 函数指针?)
【发布时间】:2014-08-17 05:31:13
【问题描述】:

原始问题(参见下面的解决方案):

我正在尝试在我的 Swift 应用程序中使用 AddressBook.framework,但不知道如何实现 ABAddressBookRegisterExternalChangeCallback 函数。

在 Objective-C 中,我只是将回调实现为 C 函数并传递它的指针:

// somewhere in the initializer of the MyAddressBook class:
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, nil);
ABAddressBookRegisterExternalChangeCallback(addressBook, externalChangeCallback, (__bridge void *)(self));

// somewhere else in the MyAddressBook class:
void externalChangeCallback(ABAddressBookRef reference, CFDictionaryRef info, void *context)
{
    [(__bridge MyAddressBook *)context addressBookDidChangeExternally];
}

- (void)addressBookDidChangeExternally
{
    // good old Obj-C from here on!
}

在 Swift 中,事实证明我很难处理 C 函数。我发现 Apple 在 beta 3 中添加了传递 C 函数指针的功能,但是我该如何声明这样的函数呢?使用 Swift 的闭包语法会很好,但在这里甚至可以吗?

这是我创建ABAddressBookRef的地方:

var addressBookRef: ABAddressBookRef = {
    let addressBookRef: ABAddressBookRef = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()

    // TODO: how do I make this work?
    let externalChangeCallback: ABExternalChangeCallback = {
        println("Address book changed externally!")
    }
    ABAddressBookRegisterExternalChangeCallback(addressBookRef, externalChangeCallback, nil)

    return addressBookRef
}()

那么我该如何在 Swift 中实现呢?


解决方案(有缺陷):

按照 pNre 的建议,我现在是这样实现的:

在 Objective-C 中:

AddressBookExternalChangeCallback.h:

#import <AddressBook/AddressBook.h>
void registerExternalChangeCallbackForAddressBook(ABAddressBookRef addressBookRef);

AddressBookExternalChangeCallback.m:

#import "AddressBookExternalChangeCallback.h"

void addressBookExternalChangeCallback(ABAddressBookRef addressBookRef, CFDictionaryRef info, void *context)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:@"AddressBookDidChangeExternallyNotification" object:nil];
    });
}

void registerExternalChangeCallbackForAddressBook(ABAddressBookRef addressBookRef)
{
    ABAddressBookRegisterExternalChangeCallback(addressBookRef, addressBookExternalChangeCallback, nil);
}

在 Swift 中:

导入桥接头后:

registerExternalChangeCallbackForAddressBook(addressBookRef)

只要地址簿发生更改,就会发布通知。不过,只有 @objc 类可以注册通知,所以有没有办法调用 Swift 函数或方法?

【问题讨论】:

  • 那么你是怎么完成的?我确实在桥接头和类型别名 ABExternalChangeCallback = CFunctionPointer) -> Void)> 在我的 swift 类中全局声明了 registerExternalChangeCallbackForAddressBook(addressBookRef) 接下来如何在 Swift 中调用 registerExternalChangeCallbackForAddressBook ?请您发布您对 swift 的详细答案,这对像我这样的用户非常有帮助。

标签: swift abaddressbook


【解决方案1】:

ABExternalChangeCallback 定义为

typealias ABExternalChangeCallback = CFunctionPointer<((ABAddressBookRef!, CFDictionary!, UnsafeMutablePointer<()>) -> Void)>

来自 Xcode 发行说明:

但是,您不能调用 C 函数指针 (CFunctionPointer) 或 将闭包转换为 C 函数指针类型。

这意味着您不能按照自己的方式分配块。 但是,您可以绕过此限制,在 objc 函数中调用 ABAddressBookRegisterExternalChangeCallback 并从您的 swift 代码中调用它。

【讨论】:

    【解决方案2】:

    斯威夫特 2.0

    if let addressBook = ABAddressBookCreateWithOptions(nil, nil) {
        let ref = addressBook.takeRetainedValue()
        let callback: @convention(c) (addressBookRef: ABAddressBookRef!, info: CFDictionaryRef!, context: UnsafeMutablePointer<Void>) -> Void = {
            (addressBookRef, info, context) in
    
            // do the things you want
    
        }
    
        let addressBookChangeCallback = unsafeBitCast(callback, ABExternalChangeCallback.self)
    
        ABAddressBookRegisterExternalChangeCallback(ref, addressBookChangeCallback, nil)
    
    }
    

    【讨论】:

    • 代码构造构建并运行,但在任何联系人更改时都不会触发。
    【解决方案3】:

    在 Swift 4.0 中

    class ABAddressBookManager: NSObject {
    
        static let shared = ABAddressBookManager()
    
        private var addressBook: ABAddressBook?
    
        override init() {
            super.init()
    
            let addressBookForObserving = ABAddressBookCreate().takeRetainedValue()
            let context = Unmanaged.passUnretained(self).toOpaque()
    
            DispatchQueue.main.async {
                 ABAddressBookRegisterExternalChangeCallback(addressBookForObserving, { (addressBook, info, context) in 
                    guard let context = context else {
                        return
                    }
                    let manager = Unmanaged<ABAddressBookManager>.fromOpaque(context).takeUnretainedValue()
                    //call manager's method
                }
            }
            self.addressBook = addressBookForObserving
        }
    }
    

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题。但是我已经通过在地址簿对象中调用 ABAddressBookRevert() 清除了缓存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-10
        相关资源
        最近更新 更多