4

FSEventStream の基本を機能させることに成功し、新しいファイル イベントのフォルダーを監視できるようになりました。残念ながら、私が FSEventStreamCreate() に渡しているコールバック参照が失われている/破損している/保持されていないため、必要なデータ オブジェクトにもアクセスできません。キーコードブロックは次のとおりです。

FileWatcher.m : (FSEvent ストリームのセットアップ)

FSEventStreamContext context;
//context.info = (__bridge_retained void *)(uploadQueue);  // this didn't help
context.info = CFBridgingRetain(uploadQueue);
context.version = 0;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;

/* Create the stream, passing in a callback */
stream = FSEventStreamCreate(NULL,
                             &FileWatcherCallback,
                             &context,
                             pathsToWatch,
                             kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
                             latency,
                             kFSEventStreamCreateFlagFileEvents /* Also add kFSEventStreamCreateFlagIgnoreSelf if lots of recursive callbacks */
                             );

Filewatcher.m: FileWatcherCallback

void FileWatcherCallback(
                     ConstFSEventStreamRef streamRef,
                     FSEventStreamContext *clientCallBackInfo,
                     size_t numEvents,
                     void *eventPaths,
                     const FSEventStreamEventFlags eventFlags[],
                     const FSEventStreamEventId eventIds[])
{
    int i;
    char **paths = eventPaths;

    // Retrieve pointer to the download Queue!
    NSMutableDictionary *queue = (NSMutableDictionary *)CFBridgingRelease(clientCallBackInfo->info);
    // Try adding to the queue
    [queue setValue:@"ToDownload" forKey:@"donkeytest" ];
    ...
}

このコールバック関数が起動されると、ファイル パスを正常に取得できますが、NSMutableDictionary への clientCallBackInfo->info ポインターは、ストリームをセットアップしたときとは異なるメモリ アドレスを指しています。次に辞書に追加しようとすると、例外がスローされます (setValue 行)。

何らかの方法でポインターを別の方法で処理する必要がありますか? どんな助けでも大歓迎です。(私は、ARCを含むデフォルトのビルド設定でXcode 4.5.1を使用しています。)

4

2 に答える 2

2

コールバック関数の 2 番目の引数はvoid *info(これは) であり、構造体context.infoへのポインターではありません。FSEventStreamContext context

したがって、このコードは正しいポインターを取得するために機能するはずです。

void FileWatcherCallback(
                         ConstFSEventStreamRef streamRef,
                         void *info, // <-- this is context.info
                         size_t numEvents,
                         void *eventPaths,
                         const FSEventStreamEventFlags eventFlags[],
                         const FSEventStreamEventId eventIds[])
{
    // ...
    // Retrieve pointer to the download queue:
    NSMutableDictionary *queue = CFBridgingRelease(info);
    // ...
}

備考:CFBridgingRetain() /の使い方には別の問題があるようですCFBridgingRelease()。オブジェクトの保持カウントは、コールバック関数が呼び出されるたびuploadQueueに減少します。これにより、非常に迅速にクラッシュが発生します。

使ったほうがいいかもしれません

context.info = (__bridge void *)(uploadQueue);

イベント ストリームの作成、および

NSMutableDictionary *queue = (__bridge NSMutableDictionary *)info;

コールバック関数で。uploadQueueイベント ストリームが使用されている限り、強力な参照を維持することだけを確認する必要があります。

于 2012-11-29T18:59:22.570 に答える
0

私はこの API を使用したことがありませんが、インターネット上の例を見るとself、このポインターを渡すのが普通のようです。次に、uploadQueueがインスタンス変数である場合は、プロパティを介してアクセスできるようにすることができます (また、クラス インスタンス内のすべてにアクセスできるという利点もあります)。

于 2012-11-29T15:05:56.810 に答える