目标C类中的混合C函数
我正在编写一个Objective-C类,但它使用了一个用C编写的API。这基本上是好的,因为混合使用C调用和Objective-C调用会导致很少的问题 但是,其中一个API调用需要回调方法(示例): 其中目标C类中的混合C函数,c,objective-c,cocoa,callback,C,Objective C,Cocoa,Callback,我正在编写一个Objective-C类,但它使用了一个用C编写的API。这基本上是好的,因为混合使用C调用和Objective-C调用会导致很少的问题 但是,其中一个API调用需要回调方法(示例): 其中MyCFHostClientCallBack是定义如下的C函数: static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info)
MyCFHostClientCallBack
是定义如下的C函数:
static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info);
在这种情况下,我总是发现在C API之上制作一个Obj-C包装器很有帮助。使用C函数实现您需要的功能,并在其上构建一个Objective-C类(或两个),这就是外部世界将看到的所有内容。例如,在这种回调的情况下,您可以创建一个C函数,在其他对象上调用Obj-C委托方法。要从C回调调用Objective-C代码,我将使用以下方法:
void * refToSelf;
int cCallback()
{
[refToSelf someMethod:someArg];
}
@implementation SomeClass
- (id) init
{
self = [super init];
refToSelf = self;
}
- (void) someMethod:(int) someArg
{
}
混合使用C和Objective-C方法和函数是可能的,下面是一个在iPhone应用程序中使用SQLite API的简单示例:() 下载 C函数需要在Objective-C(.m)文件中的
@实现之外声明
因为C函数在@实现之外
它不能调用
[self doSomething]
而且无法访问IVAR
只要回调函数采用userInfo
或context
类型参数(通常为void*
类型),就可以解决这个问题。这可用于将任何Objective-C对象发送到C函数
与中一样,这可以通过正常的Objective-C操作进行操作
此外,请阅读以下答案:
我可以/如何调用Objective-C方法来代替此方法
你不能
我可以/应该将C函数与Objective-C调用混合使用吗
对。编写一个C函数并将其用作CF函数的回调
如何将C函数与Objective-C方法混合
您可以将self
设置为上下文结构中的info
指针。这将传递给回调。然后,在回调中,将info
指针投射回id
:
MyClass *self = (id)info;
然后,您可以发送self
消息。但是,您仍然不能直接访问实例变量,因为C函数不在@implementation
部分。你必须让它们成为你的财产。你可以用一只手来做这件事。(与该文档所说的相反,您不会在@implementation
中声明扩展名,而是在与其相同的文件中声明扩展名,通常位于扩展名的正上方。)只需添加一项:许多回调允许指定“用户数据”;在这种情况下,对象指针可以用作用户数据(并且不再需要全局变量refToSelf)。可能是您的回调函数支持info指针中的“用户数据”。使用上述代码,我收到运行时内存泄漏警告,并启用了ARC。这是错误的实现。它假定您只有一个ComeClass实例。void*refToSelf;是一个静态/全局变量。每次[[SomeClass alloc]init]您的refToSelf都将被创建的最后一个实例覆盖。cCallback不会调用正确的SomeClass,而是始终调用最后创建的SomeClass。此外,当最后创建的SomeClass被释放时(至少在上面的代码中),它将崩溃,因为您在SomeClass的dealloc中没有清除refToSelf。要补充@ashcatch所说的:如果您的回调被赋予了void*userData
,请确保使用(_桥id)(用户数据)
以避免警告和泄漏。如果某个类是单例的,这是可以的。但它不是单例的,请同意@MottiShneor answer。C函数不需要在@implementation
@bavariable:编译器允许您避开@implementation
内部的函数,但它仍然不是@implementation的一部分e> ,因为函数不能属于一个类。作为一种风格,我把它放在@implementation
之外,并建议其他人也这样做,以明确这一点。实际上,@implementation块中的C函数具有独特的属性,能够直接访问私有和受保护的IVAR。因此,根据我自己的经验,它是我有一个很强的习惯用法,将“属于”类的C函数放在相应的实现中。我建议更新您的答案。为了澄清,如果允许它们访问类的实例,它们将可以访问私有IVAR。例如,int-MyCFunction(MyClass*self、int-num、void*data)。这与编译-myObjectiveMethod:withData:objc方法时的幕后情况非常相似。@JoshRosen:很有趣,但我认为这只是一个实现细节,而不是明确定义并保证存在的语言功能。
[self doSomething]
MyClass *self = (id)info;