Есть ли делегат в Swift, который позволил бы моему классу узнать, когда новые устройства подключены через USB-порт компьютера? Я хотел бы знать, когда новое устройство станет доступным для моей программы.Делегат USB-соединения на Swift
ответ
Этот ответ сработал для меня https://stackoverflow.com/a/35788694, но для этого потребовалась адаптация, например, создание заголовка моста для импорта определенных частей IOKit.
Сначала добавьте в проект проект IOKit.framework (нажмите «+» в «Связанные структуры и библиотеки»).
Затем создайте новый пустой файл «.m», независимо от его имени. Затем Xcode спросит, должен ли он сделать «мостовой заголовок». Скажи да.
Игнорировать файл «.m». В новом файле «YOURAPPNAME-Bridging-header.h», что Xcode только что создали, добавьте следующие строки:
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/hid/IOHIDKeys.h>
Теперь вы можете использовать код в связанном ответе. Вот упрощенная версия:
class USBDetector {
class func monitorUSBEvent() {
var portIterator: io_iterator_t = 0
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
let gNotifyPort: IONotificationPortRef = IONotificationPortCreate(kIOMasterPortDefault)
let runLoopSource: Unmanaged<CFRunLoopSource>! = IONotificationPortGetRunLoopSource(gNotifyPort)
let gRunLoop: CFRunLoop! = CFRunLoopGetCurrent()
CFRunLoopAddSource(gRunLoop, runLoopSource.takeRetainedValue(), kCFRunLoopDefaultMode)
let observer = UnsafeMutablePointer<Void>(unsafeAddressOf(self))
_ = IOServiceAddMatchingNotification(gNotifyPort,
kIOMatchedNotification,
matchingDict,
deviceAdded,
observer,
&portIterator)
deviceAdded(nil, iterator: portIterator)
_ = IOServiceAddMatchingNotification(gNotifyPort,
kIOTerminatedNotification,
matchingDict,
deviceRemoved,
observer,
&portIterator)
deviceRemoved(nil, iterator: portIterator)
}
}
func deviceAdded(refCon: UnsafeMutablePointer<Void>, iterator: io_iterator_t) {
var kr: kern_return_t = KERN_FAILURE
while case let usbDevice = IOIteratorNext(iterator) where usbDevice != 0 {
let deviceNameAsCFString = UnsafeMutablePointer<io_name_t>.alloc(1)
defer {deviceNameAsCFString.dealloc(1)}
kr = IORegistryEntryGetName(usbDevice, UnsafeMutablePointer(deviceNameAsCFString))
if kr != KERN_SUCCESS {
deviceNameAsCFString.memory.0 = 0
}
let deviceName = String.fromCString(UnsafePointer(deviceNameAsCFString))
print("Active device: \(deviceName!)")
IOObjectRelease(usbDevice)
}
}
func deviceRemoved(refCon: UnsafeMutablePointer<Void>, iterator: io_iterator_t) {
// ...
}
Примечание: deviceAdded
и deviceRemoved
должны быть функции (не методы).
Чтобы использовать этот код, просто запустите обозреватель:
USBDetector.monitorUSBEvent()
Это будут перечислены в настоящее время подключены устройства, и на каждом новом штекером USB устройства/отсоединяйте случае он будет выводить имя устройства.
Это написано для Swift 2.2? Я пытаюсь заставить это работать в Swift 3, но безуспешно:/Любые идеи об изменениях, которые нужно будет сделать? – simonthumper
Да, просьба указать пример Swift 3. Спасибо – Arti
Я поставил щедрость на этот вопрос - будем надеяться, что мы получим интересный ответ Свифта 3. – Moritz
Ответ Эрика Айи уже неплохой, но вот адаптация Swift 3. Я завернул большую часть уродливых вещей в классе USBWatcher
; задайте себя как делегат этого объекта для получения уведомлений.
Вы можете скопировать/вставить следующее на игровое поле, чтобы увидеть, как оно работает - пример просто регистрирует сообщение на консоли, когда устройства подключены/отключены.
К сожалению, API-интерфейсы IOKit не получили того же метода Swift-ifying, что и другие C API-интерфейсы (например, CoreGraphics). io_name_t
- это неуклюжий кортеж вместо правильной структуры, способ, которым C-структуры обычно импортируются в Swift; io_object_t
не является реальным ссылочным типом, поэтому он не может использовать ARC. Возможно, в будущем это изменится - если вы хотите увидеть лучший Swift API, вы должны file an enhancement request.
import Foundation
import IOKit
import IOKit.usb
public protocol USBWatcherDelegate: class {
/// Called on the main thread when a device is connected.
func deviceAdded(_ device: io_object_t)
/// Called on the main thread when a device is disconnected.
func deviceRemoved(_ device: io_object_t)
}
/// An object which observes USB devices added and removed from the system.
/// Abstracts away most of the ugliness of IOKit APIs.
public class USBWatcher {
private weak var delegate: USBWatcherDelegate?
private let notificationPort = IONotificationPortCreate(kIOMasterPortDefault)
private var addedIterator: io_iterator_t = 0
private var removedIterator: io_iterator_t = 0
public init(delegate: USBWatcherDelegate) {
self.delegate = delegate
func handleNotification(instance: UnsafeMutableRawPointer?, _ iterator: io_iterator_t) {
let watcher = Unmanaged<USBWatcher>.fromOpaque(instance!).takeUnretainedValue()
let handler: ((io_iterator_t) -> Void)?
switch iterator {
case watcher.addedIterator: handler = watcher.delegate?.deviceAdded
case watcher.removedIterator: handler = watcher.delegate?.deviceRemoved
default: assertionFailure("received unexpected IOIterator"); return
}
while case let device = IOIteratorNext(iterator), device != IO_OBJECT_NULL {
handler?(device)
IOObjectRelease(device)
}
}
let query = IOServiceMatching(kIOUSBDeviceClassName)
let opaqueSelf = Unmanaged.passUnretained(self).toOpaque()
// Watch for connected devices.
IOServiceAddMatchingNotification(
notificationPort, kIOMatchedNotification, query,
handleNotification, opaqueSelf, &addedIterator)
handleNotification(instance: opaqueSelf, addedIterator)
// Watch for disconnected devices.
IOServiceAddMatchingNotification(
notificationPort, kIOTerminatedNotification, query,
handleNotification, opaqueSelf, &removedIterator)
handleNotification(instance: opaqueSelf, removedIterator)
// Add the notification to the main run loop to receive future updates.
CFRunLoopAddSource(
CFRunLoopGetMain(),
IONotificationPortGetRunLoopSource(notificationPort).takeUnretainedValue(),
.commonModes)
}
deinit {
IOObjectRelease(addedIterator)
IOObjectRelease(removedIterator)
IONotificationPortDestroy(notificationPort)
}
}
extension io_object_t {
/// - Returns: The device's name.
func name() -> String? {
let buf = UnsafeMutablePointer<io_name_t>.allocate(capacity: 1)
defer { buf.deallocate(capacity: 1) }
return buf.withMemoryRebound(to: CChar.self, capacity: MemoryLayout<io_name_t>.size) {
if IORegistryEntryGetName(self, $0) == KERN_SUCCESS {
return String(cString: $0)
}
return nil
}
}
}
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class Example: USBWatcherDelegate {
private var usbWatcher: USBWatcher!
init() {
usbWatcher = USBWatcher(delegate: self)
}
func deviceAdded(_ device: io_object_t) {
print("device added: \(device.name() ?? "<unknown>")")
}
func deviceRemoved(_ device: io_object_t) {
print("device removed: \(device.name() ?? "<unknown>")")
}
}
let example = Example()
Удивительный ответ, спасибо большое! Я не уверен, что я действительно понимаю управление памятью здесь, например 'let watcher = Unmanaged
@EricAya: непрозрачные указатели - это способ «туннелировать» ссылку на экземпляр класса через функции C. Он часто используется в связи с функциями/замыканиями, которые используются как обратные вызовы C и не могут фиксировать контекст. Сравните (и я приношу свои извинения за саморекламу) http://stackoverflow.com/questions/33294620/how-to-cast-self-to-unsafemutablepointervoid-type-in-swift и http://stackoverflow.com/ вопросы/33260808/swift-proper-use-of-cfnotificationcenteraddobserver-w-callback для другого примера, который демонстрирует использование. –
@MartinR Эти 'bridge()' помощники довольно круты! Я не думал об этом. Перегрузка делает это довольно приятным. – jtbandes
- 1. swift UINavigationController делегат
- 2. Делегат декларация Swift
- 3. Swift: Как использовать делегат
- 4. Делегат Ошибка в Swift
- 5. willDisplayCell делегат метод Swift
- 6. Swift Делегат не называется
- 7. Swift Делегат без подготовкиForSegue
- 8. Текстовое поле делегат swift
- 9. Общий делегат в Swift
- 10. swift: делегат nil после segue
- 11. Невосприимчивый делегат потока в Swift
- 12. Objective C Делегат в Swift
- 13. Swift 2.0: Делегат не работает
- 14. Swift NSURLSession делегат в закрытии
- 15. Swift Делегат в собственном классе
- 16. Swift: делегат коллекцииviewHeader не работает?
- 17. Swift - ImagePicker не выполняет делегат
- 18. Swift Общий класс как делегат
- 19. Swift - установить делегат для одноплодной
- 20. Swift googlemaps Делегат ZOOM (слушатель)
- 21. Настройка проблемы CABasicAnimation делегат в Swift 3?
- 22. Невозможно переопределить делегат собственности в Swift
- 23. Присвоение значения поисковой панели Делегат - Swift
- 24. Swift EXC_BAD_INSTRUCTION при попытке использовать делегат
- 25. Swift: как делегат приложения получит ссылку на контроллер просмотра?
- 26. Swift 3 - Как назначить делегат для UIScrollView на .xib-файле?
- 27. Делегат должен ответить на locationManager: didUpdateLocations swift eroor
- 28. UITableView делегат с использованием расширений swift
- 29. Swift; делегат встроенный контроллер просмотра и родительский
- 30. Делегат между контейнером и ViewController в Swift
Ищите «NSWorkspace» Ключи пользователя. [link] (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSWorkspace_Class/#//apple_ref/doc/constant_group/Volume_Mounting_Notification_User_Info_Keys) – Khundragpan
Собственно, ваш код будет делегатом , методы которого будут вызываться в разные моменты времени. Я не уверен, что называется владельцем делегата, хотя – Alexander
Возможный дубликат http://stackoverflow.com/questions/34628464/how-to-implement-ioservicematchingcallback-in-swift/39662693 – jtbandes