将Objective-C与C和代码组织混合

时间:2012-07-18 20:40:16

标签: objective-c c callback

我正在使用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)

谢谢你的时间!

2 个答案:

答案 0 :(得分: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];

};

答案 1 :(得分:1)

你是对的,那段代码很难看。但是,桥接C和Obj-C是no small task,所以你真的只有几个选项:

  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的作用。