【问题标题】:Notification of changes to the iPhone's /Documents directoryiPhone 的 /Documents 目录的更改通知
【发布时间】:2010-07-05 19:48:30
【问题描述】:

我们有一个使用文件共享的应用程序。设置了 UIFileSharingEnable 等等,这一切似乎都工作正常,但我正在寻找某种关于何时在 iPhone 端添加/删除文件的通知。谁能给点建议?

提前干杯。

【问题讨论】:

    标签: iphone notifications file-sharing


    【解决方案1】:

    Apple 开发者论坛上的This thread 可能会引起您的兴趣,建议您在其自己的线程中运行kqueue,跟踪应用程序的 Documents 文件夹。

    一位苹果技术人员跟进了一些sample code here

    - (void)kqueueFired
    {
        int             kq;
        struct kevent   event;
        struct timespec timeout = { 0, 0 };
        int             eventCount;
    
        kq = CFFileDescriptorGetNativeDescriptor(self->_kqRef);
        assert(kq >= 0);
    
        eventCount = kevent(kq, NULL, 0, &event, 1, &timeout);
        assert( (eventCount >= 0) && (eventCount < 2) );
    
        if (eventCount == 1) {
            NSLog(@"dir changed");
        }    
    
        CFFileDescriptorEnableCallBacks(self->_kqRef, kCFFileDescriptorReadCallBack);
    }
    
    static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info)
    {
        ViewController *    obj;
    
        obj = (ViewController *) info;
        assert([obj isKindOfClass:[ViewController class]]);
        assert(kqRef == obj->_kqRef);
        assert(callBackTypes == kCFFileDescriptorReadCallBack);
    
        [obj kqueueFired];
    }
    
    - (IBAction)testAction:(id)sender
    {
        #pragma unused(sender)
        NSString *              docPath;
        int                     dirFD;
        int                     kq;
        int                     retVal;
        struct kevent           eventToAdd;
        CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
        CFRunLoopSourceRef      rls;
    
        docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        assert(docPath != 0);
    
        NSLog(@"%@", docPath);
    
        dirFD = open([docPath fileSystemRepresentation], O_EVTONLY);
        assert(dirFD >= 0);
    
        kq = kqueue();
        assert(kq >= 0);
    
        eventToAdd.ident  = dirFD;
        eventToAdd.filter = EVFILT_VNODE;
        eventToAdd.flags  = EV_ADD | EV_CLEAR;
        eventToAdd.fflags = NOTE_WRITE;
        eventToAdd.data   = 0;
        eventToAdd.udata  = NULL;
    
        retVal = kevent(kq, &eventToAdd, 1, NULL, 0, NULL);
        assert(retVal == 0);
    
        assert(self->_kqRef == NULL);
    
        self->_kqRef = CFFileDescriptorCreate(NULL, kq, true, KQCallback, &context);
        assert(self->_kqRef != NULL);
    
        rls = CFFileDescriptorCreateRunLoopSource(NULL, self->_kqRef, 0);
        assert(rls != NULL);
    
        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
    
        CFRelease(rls);
    
        CFFileDescriptorEnableCallBacks(self->_kqRef, kCFFileDescriptorReadCallBack);
    }
    

    【讨论】:

    • 您需要包含这些标题:#include &lt;sys/stat.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/event.h&gt; #include &lt;sys/time.h&gt; #include &lt;fcntl.h&gt;
    • 如果我想监视和查找文件夹中的文件调用某些函数时,我把这三个函数放在哪里,在 appdelegate 类或什么中
    • @Alex Reynolds - 有没有办法延迟通知,直到文件写入磁盘?我有一个随机崩溃,这是由在实际写入之前读取的文件引起的。
    【解决方案2】:

    这是使用 Grand Central Dispatch (GCD) 的替代解决方案,它允许您从 NSNotificationCenter 接收文件更改通知:

    将这些变量添加到类的接口中:

    // Dispatch queue
    dispatch_queue_t _dispatchQueue;
    
    // A source of potential notifications
    dispatch_source_t _source;
    

    将以下代码添加到实现中:

        #define fileChangedNotification @"fileChangedNotification"
    
        // Get the path to the home directory
        NSString * homeDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    
        // Create a new file descriptor - we need to convert the NSString to a char * i.e. C style string
        int filedes = open([homeDirectory cStringUsingEncoding:NSASCIIStringEncoding], O_EVTONLY);
    
        // Create a dispatch queue - when a file changes the event will be sent to this queue
        _dispatchQueue = dispatch_queue_create("FileMonitorQueue", 0);
    
        // Create a GCD source. This will monitor the file descriptor to see if a write command is detected
        // The following options are available
    
        /*!
         * @typedef dispatch_source_vnode_flags_t
         * Type of dispatch_source_vnode flags
         *
         * @constant DISPATCH_VNODE_DELETE
         * The filesystem object was deleted from the namespace.
         *
         * @constant DISPATCH_VNODE_WRITE
         * The filesystem object data changed.
         *
         * @constant DISPATCH_VNODE_EXTEND
         * The filesystem object changed in size.
         *
         * @constant DISPATCH_VNODE_ATTRIB
         * The filesystem object metadata changed.
         *
         * @constant DISPATCH_VNODE_LINK
         * The filesystem object link count changed.
         *
         * @constant DISPATCH_VNODE_RENAME
         * The filesystem object was renamed in the namespace.
         *
         * @constant DISPATCH_VNODE_REVOKE
         * The filesystem object was revoked.
         */
    
        // Write covers - adding a file, renaming a file and deleting a file...
        _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,filedes,
                                                           DISPATCH_VNODE_WRITE,
                                                           _dispatchQueue);
    
    
        // This block will be called when teh file changes
        dispatch_source_set_event_handler(_source, ^(){
            // We call an NSNotification so the file can change can be detected anywhere
            [[NSNotificationCenter defaultCenter] postNotificationName:fileChangedNotification object:Nil];
        });
    
        // When we stop monitoring the file this will be called and it will close the file descriptor
        dispatch_source_set_cancel_handler(_source, ^() {
            close(filedes);
        });
    
        // Start monitoring the file...
        dispatch_resume(_source);
    
        //...
    
        // When we want to stop monitoring the file we call this
        //dispatch_source_cancel(source);
    
    
        // To recieve a notification about the file change we can use the NSNotificationCenter
        [[NSNotificationCenter defaultCenter] addObserverForName:fileChangedNotification object:Nil queue:Nil usingBlock:^(NSNotification * notification) {
            NSLog(@"File change detected!");
        }];
    

    【讨论】:

    • 注意——写入文件atomically 似乎会中断未来的通知传递。我认为文件的原子替换关闭了文件描述符
    • 它工作!我在 dispatch_async 中运行它,如下面的代码: dispatch_async(dispatch_get_main_queue(), ^{ //Method from implementation });感谢您的解决方案。
    • 我有一台使用这种方法的旧显示器,我刚刚通过使用 Combine 进行升级。 github.com/kennethlaskoski/FileSystemEventPublisher
    • 如何获取被修改的文件名?
    【解决方案3】:

    老问题,但我遇到了this Apple code,其中包括一个目录监视器。请注意,它会在添加(或删除)文件的那一刻触发;这可能是在操作系统完成写入文件之前。

    【讨论】:

    • 如何等到文件被完全写入,因为它会提前触发,当我访问它时,我会得到一个 SIGABRT。
    猜你喜欢
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 2010-11-04
    相关资源
    最近更新 更多