我正在使用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)。所以这是我的问题:
谢谢你的时间!
答案 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,所以你真的只有几个选项:
围绕基于C的API创建Objective-C包装器。这将是我推荐的方法,特别是如果API不太复杂。它为您提供了使用委托或块而不是函数的优势。
通过获取内部函数指针来使用块进行回调:
// 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");
}
}
在大多数情况下,我真的不认为这是实用的,但是如果你能找到一种方法让它发挥作用,那么对你来说就更有力量了。
坚持你目前的做法。它很糟糕,但这就是C的作用。