当前位置:  开发笔记 > IOS > 正文

如何在Swift中实现IOServiceMatchingCallBack

如何解决《如何在Swift中实现IOServiceMatchingCallBack》经验,为你挑选了1个好方法。



1> Mecki..:

这是一个Swift 3版本,使用闭包而不是全局函数(没有上下文的闭包可以桥接到C函数指针),使用GCD而不是Runloops(更好的API),使用回调和调度来通知事件和使用真实对象而不是静态对象或单例:

import Darwin
import IOKit
import IOKit.usb
import Foundation


class IOUSBDetector {

    enum Event {
        case Matched
        case Terminated
    }

    let vendorID: Int
    let productID: Int

    var callbackQueue: DispatchQueue?

    var callback: (
        ( _ detector: IOUSBDetector,  _ event: Event,
            _ service: io_service_t
        ) -> Void
    )?


    private
    let internalQueue: DispatchQueue

    private
    let notifyPort: IONotificationPortRef

    private
    var matchedIterator: io_iterator_t = 0

    private
    var terminatedIterator: io_iterator_t = 0


    private
    func dispatchEvent (
        event: Event, iterator: io_iterator_t
    ) {
        repeat {
            let nextService = IOIteratorNext(iterator)
            guard nextService != 0 else { break }
            if let cb = self.callback, let q = self.callbackQueue {
                q.async {
                    cb(self, event, nextService)
                    IOObjectRelease(nextService)
                }
            } else {
                IOObjectRelease(nextService)
            }
        } while (true)
    }


    init? ( vendorID: Int, productID: Int ) {
        self.vendorID = vendorID
        self.productID = productID
        self.internalQueue = DispatchQueue(label: "IODetector")

        let notifyPort = IONotificationPortCreate(kIOMasterPortDefault)
        guard notifyPort != nil else { return nil }

        self.notifyPort = notifyPort!
        IONotificationPortSetDispatchQueue(notifyPort, self.internalQueue)
    }

    deinit {
        self.stopDetection()
    }


    func startDetection ( ) -> Bool {
        guard matchedIterator == 0 else { return true }

        let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
            as NSMutableDictionary
        matchingDict[kUSBVendorID] = NSNumber(value: vendorID)
        matchingDict[kUSBProductID] = NSNumber(value: productID)

        let matchCallback: IOServiceMatchingCallback = {
            (userData, iterator) in
                let detector = Unmanaged
                    .fromOpaque(userData!).takeUnretainedValue()
                detector.dispatchEvent(
                    event: .Matched, iterator: iterator
                )
        };
        let termCallback: IOServiceMatchingCallback = {
            (userData, iterator) in
                let detector = Unmanaged
                    .fromOpaque(userData!).takeUnretainedValue()
                detector.dispatchEvent(
                    event: .Terminated, iterator: iterator
                )
        };

        let selfPtr = Unmanaged.passUnretained(self).toOpaque()

        let addMatchError = IOServiceAddMatchingNotification(
            self.notifyPort, kIOFirstMatchNotification,
            matchingDict, matchCallback, selfPtr, &self.matchedIterator
        )
        let addTermError = IOServiceAddMatchingNotification(
            self.notifyPort, kIOTerminatedNotification,
            matchingDict, termCallback, selfPtr, &self.terminatedIterator
        )

        guard addMatchError == 0 && addTermError == 0 else {
            if self.matchedIterator != 0 {
                IOObjectRelease(self.matchedIterator)
                self.matchedIterator = 0
            }
            if self.terminatedIterator != 0 {
                IOObjectRelease(self.terminatedIterator)
                self.terminatedIterator = 0
            }
            return false
        }

        // This is required even if nothing was found to "arm" the callback
        self.dispatchEvent(event: .Matched, iterator: self.matchedIterator)
        self.dispatchEvent(event: .Terminated, iterator: self.terminatedIterator)

        return true
    }


    func stopDetection ( ) {
        guard self.matchedIterator != 0 else { return }
        IOObjectRelease(self.matchedIterator)
        IOObjectRelease(self.terminatedIterator)
        self.matchedIterator = 0
        self.terminatedIterator = 0
    }
}

这里有一些简单的测试代码来测试该类(设置适合您的USB设备的产品和供应商ID):

let test = IOUSBDetector(vendorID: 0x4e8, productID: 0x1a23)
test?.callbackQueue = DispatchQueue.global()
test?.callback = {
    (detector, event, service) in
        print("Event \(event)")
};
_ = test?.startDetection()
while true { sleep(1) }

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有