从Swift处理FSEventStreamRef API中的可选项

时间:2019-02-18 17:19:33

标签: swift macos

我正在尝试观察一个文件夹,以查看Mac OS上该文件夹中是否创建,修改/删除了文件等。我已经读到我要使用的是文件系统事件,但是我无法使我的代码正常工作。

我曾尝试阅读docs at apple并阅读关于stackoverflow的不同文章,但我发现在swift 4和xcode 10上似乎没有任何作用。

    init(path: String) {
        let allocator: CFAllocator? = kCFAllocatorDefault

        // Create FSEventStream and return valid FSEventStreamRef
        // Alias FSEventStreamCallback - CFunction

        typealias FSEventStreamCallback = @convention(c) (ConstFSEventStreamRef, UnsafeMutableRawPointer?, Int, UnsafeMutableRawPointer, UnsafePointer<FSEventStreamEventFlags>, UnsafePointer<FSEventStreamEventId>) -> Void


        let callback: FSEventStreamCallback = {
            (streamRef, clientCallBackInfo, numEvents, eventPaths, eventFlags, eventIds) -> Void in
            print ("changed")
            // handle file event
        }

        let context: UnsafeMutablePointer<FSEventStreamContext>? = nil
        let pathsToWatch: CFArray = [NSHomeDirectory() + path] as CFArray
        let sinceWhen: FSEventStreamEventId = UInt64(kFSEventStreamEventIdSinceNow)
        let latency: CFTimeInterval = 1.0
        let flags: FSEventStreamCreateFlags = UInt32(kFSEventStreamCreateFlagNone)
        let eventStream = FSEventStreamCreate(
            allocator,
            callback,
            context,
            pathsToWatch,
            sinceWhen,
            latency,
            flags
        )

        FSEventStreamScheduleWithRunLoop(eventStream, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode as! CFString)
        FSEventStreamStart(eventStream!)
    }

我要么收到错误

Value of optional type 'FSEventStreamRef?' (aka 'Optional<OpaquePointer>') must be unwrapped to a value of type 'FSEventStreamRef' (aka 'OpaquePointer')

当我尝试构建或

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

在运行时,如果我添加“!”到“ eventStream”

我需要更改使其运行吗?

1 个答案:

答案 0 :(得分:0)

eventStream必须解开-最好带有可选的绑定,例如

guard let eventStream = FSEventStreamCreate(...) else {
     // handle error ...
}

但是实际上导致程序崩溃的是强制转换

FSEventStreamScheduleWithRunLoop(..., CFRunLoopMode.defaultMode as! CFString)

CFRunLoopMode不是CFString,因此强制as! CFString失败。它是一个struct CFRunLoopMode: RawRepresentable,基础CFString是通过rawValue属性获得的:

FSEventStreamScheduleWithRunLoop(..., CFRunLoopMode.defaultMode.rawValue)

备注: typealias FSEventStreamCallback已在Core Services框架中定义,因此无需在类中重复该定义。