1

我正在开发一个使用 fileevent api 监视文件夹的桌面应用程序,所以基本上这是我的代码:

#import "PNAppDelegate.h"

void callback(
              ConstFSEventStreamRef streamRef,
              void *clientCallBackInfo,
              size_t numEvents,
              void *eventPaths,
              const FSEventStreamEventFlags eventFlags[],
              const FSEventStreamEventId eventIds[]) 
{
    [(__bridge PNAppDelegate *)clientCallBackInfo reloadStatus];

};

@implementation PNAppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSArray *pathsToWatch = [NSArray arrayWithObject: @"/Users/romainpouclet/Projects/foo"];

    void *appPointer = (__bridge void *)self;
    FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL};

    FSEventStreamRef stream;
    CFAbsoluteTime latency = 3.0;

    stream = FSEventStreamCreate(NULL, 
                                 &callback, 
                                 &context, 
                                 (__bridge CFArrayRef) pathsToWatch, 
                                 kFSEventStreamEventIdSinceNow, 
                                 latency, 
                                 kFSEventStreamCreateFlagNone);

    NSLog(@"Schedule with run loop");
    FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
    FSEventStreamStart(stream);
    [self reloadStatus];
}

-(void)reloadStatus
{

}

@end

没问题,它对于像这个这样简单的 POC 来说效果很好,但是感觉有点难看(而且可能是,我不太习惯混合 Objective-C 和 C)。所以这是我的问题:

  • 我应该在哪里声明我的回调?将它放在我的文件顶部感觉很奇怪,只是因为它在那里工作。
  • 是否有可能有某种基于@selector 的方法而不是回调?(我觉得他们让人放心:D)

谢谢你的时间 !

4

2 回答 2

2

为什么不将回调声明放在 PNAppDelegate.h 或它自己的头文件中(如果你不想在你的应用程序中传播它)。这样你就可以只包含头文件并将函数定义放在你想要的任何地方。这样做是标准的 C 功能。

// Header file callback.h
void callback(
              ConstFSEventStreamRef streamRef,
              void *clientCallBackInfo,
              size_t numEvents,
              void *eventPaths,
              const FSEventStreamEventFlags eventFlags[],
              const FSEventStreamEventId eventIds[]);


// PNAppDelegate.m
#import "PNAppDelegate.h"
#import "callback.h"

@implementation PNAppDelegate

...

@end

void callback(
              ConstFSEventStreamRef streamRef,
              void *clientCallBackInfo,
              size_t numEvents,
              void *eventPaths,
              const FSEventStreamEventFlags eventFlags[],
              const FSEventStreamEventId eventIds[]) 
{
    [(__bridge PNAppDelegate *)clientCallBackInfo reloadStatus];

};
于 2012-07-18T20:48:37.290 回答
1

你是对的,那个代码很丑。但是,桥接 C 和 Obj-C 并非易事,因此您实际上只有几个选择:

  1. 围绕基于 C 的 API 创建一个 Objective-C 包装器。这将是我推荐的方法,尤其是在 API 不太复杂的情况下。它为您提供了使用委托或块而不是函数的优势。

  2. 通过获取内部函数指针,使用块进行回调:

    // internal structure of a block
    struct blockPtr {
        void *__isa;
        int __flags;
        int __reserved;
        void *__FuncPtr;
        void *__descriptor;
    };
    
    int main()
    {
        @autoreleasepool {
            __block int b = 0;        
    
            void (^blockReference)(void *) = ^(void *arg) {
                NSLog(@"<%s>: %i", arg, b++);
            };
    
    
            void *blockFunc = ((__bridge struct blockPtr *) blockReference)->__FuncPtr;
            void (*castedFunction)(void *, void *) = blockFunc;
    
            // the first argument to any block funciton is the block 
            // reference itself, similar to how the first argument to
            // any objc function is 'self', however, in most cases you
            // don't need the block reference (unless reading __block variables), it's just difficult to
            // get that first argument from inside the block
            castedFunction((__bridge void *) blockReference, "one");
            castedFunction((__bridge void *) blockReference, "two");
        }
    }
    

    我真的不认为这在大多数情况下是实用的,但如果你能找到一种方法让它发挥作用,你就会更有力量。

  3. 坚持你目前的做法。这很糟糕,但这就是 C 的工作方式。

于 2012-07-18T21:01:03.180 回答