2012-07-18 39 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