On 25 Jan 2017, at 07:49, John Brownie via swift-users <swift-users@swift.org> 
wrote:

> My macOS app shows a representation of the contents of various folders, so 
> using FSEvents to track modifications from outside the app seemed to be the 
> way to go. I am running into difficulty with writing the code with a 
> callback, all in Swift.

Yep, that can be a bit tricky.  There’s two parts to this, one of which is 
relatively straightforward and the other is not something I’ve dealt with 
before:

A. Setting the `info` pointer in the context — The standard approach for this 
is as follows:

1. Set the `info` pointer like this:

context.info = Unmanaged.passRetained(self).toOpaque()

2. Convert from the `info` pointer like this:

let obj = Unmanaged<Observer>.fromOpaque(info!).takeUnretainedValue()

IMPORTANT: After this the `info` pointer is holding a reference to your self 
object.  If you shut down the stream, you need to release that pointer.  Let me 
know if that’s relevant to you (a lot of folks just start a stream and leave it 
running).

B. Dealing with FSEventStreamCallback parameters — FSEvents is weird in that 
the callback can take either an array of C strings or a CFArray of CFStrings 
depending on how you configure it.  The latter is easier, so like you I set 
`kFSEventStreamCreateFlagUseCFTypes`.

My code is pasted in below.

Share and Enjoy
--
Quinn "The Eskimo!"                    <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

---------------------------------------------------------------------------
import Foundation

class Watcher {

    var stream: FSEventStreamRef? = nil

    func start() {
        var context = FSEventStreamContext()
        context.version = 0
        context.info = Unmanaged.passRetained(self).toOpaque()
        let sinceWhen = FSEventStreamEventId(kFSEventStreamEventIdSinceNow)
        let flags = FSEventStreamCreateFlags(kFSEventStreamCreateFlagUseCFTypes)
        guard let stream = FSEventStreamCreate(nil, { (_, info, pathCount, 
rawPaths, flagsBase, eventIDsBase) in
            let obj = Unmanaged<Watcher>.fromOpaque(info!).takeUnretainedValue()
            
            let paths = 
Unmanaged<CFArray>.fromOpaque(rawPaths).takeUnretainedValue() as! [String]
            let flags = UnsafeBufferPointer(start: flagsBase, count: pathCount)
            let eventIDs = UnsafeBufferPointer(start: eventIDsBase, count: 
pathCount)
            obj.printBatch(paths: paths, flags: Array(flags), eventIDs: 
Array(eventIDs))
        }, &context, ["/"] as NSArray, sinceWhen, 1.0, flags) else {
            fatalError()
        }
        self.stream = stream
        
        FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), 
CFRunLoopMode.defaultMode.rawValue)
        
        let success = FSEventStreamStart(stream)
        assert(success)
    }
    
    func printBatch(paths: [String], flags: [FSEventStreamEventFlags], 
eventIDs: [FSEventStreamEventId]) {
        precondition(paths.count == flags.count)
        precondition(paths.count == eventIDs.count)
        NSLog("batch:")
        for i in 0..<paths.count {
            NSLog("  %08x %016llx %@", flags[i], eventIDs[i], paths[i] as 
NSString)
        }
    }
}

func main() {
    let watcher = Watcher()
    watcher.start()
    RunLoop.current.run()
}

main()
---------------------------------------------------------------------------

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to