CFReadStreamSetClient回调函数 - 如何为C回调函数提供对包含类的引用?

时间:2011-03-13 22:29:21

标签: objective-c c cocoa cocoa-touch

我正在为下面的网络读取流提供客户端回调函数:

 -(void)connectToServer
{
    if([self isServerConfigured])
    {
        CFReadStreamRef readStream; 
        CFWriteStreamRef writeStream;
        CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)self.serverAddress);
        CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host, self.port, &readStream, &writeStream);

        CFStreamClientContext myContext = {
            0,
            self,
            (void *(*)(void *info))CFRetain,
            (void (*)(void *info))CFRelease,
            (CFStringRef (*)(void *info))CFCopyDescription
        };

        CFOptionFlags registeredEvents = kCFStreamEventHasBytesAvailable |
        kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;

        if(CFReadStreamSetClient(readStream, registeredEvents, serverCB, &myContext))
        {
            CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
        }
        if(!CFReadStreamOpen(readStream)){
            NSLog(@"Could not open read stream");
        }
    }
}

我希望这个回调函数能够调用当前对象(self)中的实例函数。 CFReadStreamSetClient似乎不允许我更改回调函数签名,所以我不能只将当前对象的引用传递给我不认为的回调。

这是回调函数:

 void serverCB(CFReadStreamRef stream, CFStreamEventType event, void *myPtr)
{
    switch(event) {
        case kCFStreamEventHasBytesAvailable:
            [self readStreamData:stream];
            break;
        case kCFStreamEventErrorOccurred:
            NSLog(@"A Read Stream Error Has Occurred!");
            break;
        case kCFStreamEventEndEncountered:
            NSLog(@"A Read Stream Event End!");
            break;
        default:
            break;
    }
}

ServerCB不知道在这种情况下'self'是什么。有人能指点我如何解决这个问题吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

在这种情况下,

myPtr == self,因为self是您为上下文的info字段提供的值。然后通过最后一个参数将该字段传递给回调。所以:

void serverCB(CFReadStreamRef stream, CFStreamEventType event, void *myPtr) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    {
        MyClass *self = [[(MyClass *)myPtr retain] autorelease];

        // ...
        // ...
        // ...

    }
    [pool drain];
}

(因为这是Core Foundation级别,所以无法保证自动释放池已就绪,所以在自动释放池中包含这些回调中的Objective-C是很常见的,以防万一。)