简体   繁体   English

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

[英]Mixing Objective-C with C and code organization

I'm working on a desktop application that watch folders using the fileevent api, so basically this is my code : 我正在使用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

No problem, it works pretty well for a POC as simple as this one, BUT it feels kinda ugly (and it probably is, I'm not really used to mix Objective-C and C). 没问题,它对于像这个一样简单的POC非常有效,但它感觉有点难看(可能是,我实际上并不习惯混合使用Objective-C和C)。 So here are my questions : 所以这是我的问题:

  • where should I declare my callback? 我应该在哪里声明我的回调? It feels weird having it at the top of my file, just because it worked there. 将它放在我的文件顶部感觉很奇怪,因为它在那里工作。
  • is it possible to have some kind of @selector-based approach instead of callbacks? 是否有可能采用某种基于@ selector的方法而不是回调? (I find them reassuring :D) (我觉得他们很放心:D)

Thanks for your time ! 谢谢你的时间 !

Why not put the callback declaration in either PNAppDelegate.h, or its own header file (if you don't want to spread it around your app). 为什么不将回调声明放在PNAppDelegate.h或它自己的头文件中(如果你不想在你的应用程序中传播它)。 That way you can just include the header file and put the function definition anywhere you want. 这样你就可以只包含头文件并将函数定义放在你想要的任何地方。 Doing so is standard C functionality. 这样做是标准的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];

};

You are correct, that code IS ugly. 你是对的,那段代码很难看。 However, bridging C and Obj-C is no small task , so you really only have a few options: 但是,桥接C和Obj-C 并不是一项小任务 ,所以你真的只有几个选择:

  1. Create an Objective-C wrapper around the C-based API. 围绕基于C的API创建Objective-C包装器。 This would be my recommended approach, especially if the API is not too complex. 这将是我推荐的方法,特别是如果API不太复杂。 It gives you the advantage of using either delegates or blocks, instead of functions. 它为您提供了使用委托或块而不是函数的优势。

  2. Use blocks for callbacks, by getting their internal function pointer: 通过获取内部函数指针,使用块进行回调:

     // 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"); } } 

    I really don't think this is practical in most situations, but if you can find a way to make it work, more power to you. 在大多数情况下,我真的不认为这是实用的,但如果你能找到一种方法让它发挥作用,那么对你来说就更有力量了。

  3. Stick with how you are currently doing it. 坚持你目前的做法。 It sucks, but that is how C works. 它很糟糕,但这就是C的工作方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM