2012-07-18 58 views
1

我的工作是看使用fileevent API文件夹的桌面应用程序,所以基本上这是我的代码:混合的Objective-C与C和代码组织

#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)。所以这里是我的问题:

  • 我应该在哪里声明我的回调?感觉有点奇怪,因为它在那里工作。
  • 是否有可能有某种基于@选择器的方法而不是回调? (我觉得他们放心:D)

感谢您的时间!

+0

您可以在自己的源文件(可选地,与其他相关的C函数分组)中实现您的回调,并使用其前向声明导入标题。但是如果回调对于这个班级来说是100%特定的,并且在其他任何地方都不需要,那么这是没有意义的。 – 2012-07-18 20:53:34

+0

另外,在你的情况下,回调的主体需要访问类声明和至少一种方法。 – 2012-07-18 20:54:12

+0

感谢您的回答:) – 2012-07-19 18:30:26

回答

1

你是对的,该代码是丑陋的。然而,桥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的工作原理。

+0

什么样的包装会是什么样子?这与回调定义相同的问题,对吧? – 2012-07-19 01:42:08

+1

@Palleas它完全依赖于API。大多数回调方法都支持'context'参数,理论上它允许您将对象引用传递给函数,在这种情况下,您将有一个将消息发送到上下文参数代理的实现。 – 2012-07-19 01:45:16

+0

我明白你的意思,我喜欢调用上下文参数委托的想法。 该解决方案也很好,因为我只有一个回调...谢谢! – 2012-07-19 10:58:59

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]; 

}; 
+0

+1这是* comme il faut *。 – 2012-07-18 20:52:38

+0

这种方式似乎有点清洁。至于现在这是我唯一的回调,我不知道我需要把它放在专用文件中。谢谢! – 2012-07-19 11:00:19