iTunes中对Documents文件夹进行操作的监听方法

With iOS 4.0, AAPL brought File Sharing to the iPhone. This feature is pretty simple to turn on (basically, you just add the UIFileSharingEnabled(Application supports iTunes file sharing) key to your application’s Info.plist file and set the value of the key to YES, and then the user can access your app’s Documents directory through iTunes) but a little tricky to handle in practice.


The wrinkle is that you’ll probably want to manipulate the files that the user adds to (or removes from) the Documents directory and, since the user can update these files at any time, that means that you’ll probably want your app to monitor that directory for any changes. Such monitoring isn’t too complicated to set up, but it does require a trip into some of the more obscure parts of the BSD underpinnings of iOS.

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/event.h>

#include <sys/time.h>

#include <fcntl.h>


@property (nonatomic,assign)CFFileDescriptorRef kqRef;



- (void)beginTrackKqueue

{

   NSString *              docPath;

   int                     dirFD;

   int                     kq;

   int                     retVal;

   struct kevent           eventToAdd;

   CFFileDescriptorContext context = { 0, (__bridge void *)(self), NULLNULLNULL };

    CFRunLoopSourceRef      rls;

    

    docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMaskYES)objectAtIndex:0];

   assert(docPath != 0);

    

    dirFD = open([docPathfileSystemRepresentation], 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, 1NULL0,NULL);

   assert(retVal == 0);

    

   assert(self->_kqRef ==NULL);

    

   self->_kqRef =CFFileDescriptorCreate(NULL, kq,trueKQCallback, &context);

   assert(self->_kqRef !=NULL);

    

    rls = CFFileDescriptorCreateRunLoopSource(NULL,self->_kqRef,0);

   assert(rls != NULL);

    

    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,kCFRunLoopDefaultMode);

    

   CFRelease(rls);

    

    CFFileDescriptorEnableCallBacks(self->_kqRef,kCFFileDescriptorReadCallBack);

}



//As you can see, it doesn’t really do anything except call an object method — it only exists because you can’t pass object methods to CFFileDescriptorCreate().

staticvoid KQCallback(CFFileDescriptorRef kqRef,CFOptionFlags callBackTypes, void *info)

{

    AppDelegate *obj;

    obj = (__bridgeAppDelegate *)info;

    assert([objisKindOfClass:[AppDelegateclass]]);

   assert(kqRef == obj->_kqRef);

    assert(callBackTypes ==kCFFileDescriptorReadCallBack);

    

    [objkqueueFired];

}


//This method doesn't do anything too spectacular either; it makes sure that it can pull an event off the kqueue, and, assuming it can, calls the object's updateFns method and re-enables the CFFileDescriptor's one-shot callback. As for the updateFns method itself: this post is already punishingly long, and updateFns doesn't do anything particularly surprising. 

- (void)kqueueFired

{

   int             kq;

   structkevent   event;

   structtimespec 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) {

        [[NSNotificationCenterdefaultCenter]postNotificationName:TrackAction object:nil];

    }

    

    CFFileDescriptorEnableCallBacks(self->_kqRef,kCFFileDescriptorReadCallBack);

}



This is only a partial answer, but might be somewhat useful.


1、The kqueue mechanism indeed does work as a means to be notified when an app's Documents directory is modified.


2、The notification comes as soon as the directory is modified and before copying a file is complete. I have observed this in testing.


Unfortunately, there is no form of notification when the copy is done. At least, none that I have found.


What I hope Apple will realize is there needs to be a notification for "iTunes synch" is done, because this seems to be a general problem.


A loop checking if the new file's modification time is not changing might work, but only most of the time. In some extreme circumstances, iOS can pause to do all kinds of time consuming work of its own in the background.


If there is a way to check if a particular file is open by another process, then this would be enough.


你可能感兴趣的:(Objective-C)