在Objective-C类中混合C函数

rjs*_*ing 39 c cocoa objective-c callback

我正在编写一个Objective-C类,但是它使用了用C编写的API.这很好,因为使用Objective-C调用混合C调用几乎没有问题.

但是,其中一个API调用需要回调方法(示例):

success = CFHostSetClient(host, MyCFHostClientCallBack, &context);
Run Code Online (Sandbox Code Playgroud)

MyCFHostClientCallBackC函数在哪里定义如下:

static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info);
Run Code Online (Sandbox Code Playgroud)
  1. 可以/如何使用Objective-C方法代替此方法?
  2. 可以/我应该将C函数与Objective-C调用混合使用吗?
  3. 如何将C函数与Objective-C方法混合使用?

rjs*_*ing 49

可以混合使用C和Objective-C方法和函数,这是一个在iPhone App中使用SQLite API的简单示例:( 课程网站)

下载Zip文件(09_MySQLiteTableView.zip)

C函数需要@implementation在Objective-C(.m)文件之外声明.

int MyCFunction(int num, void *data)
{
     //code here...
}

@implementation

- (void)MyObjectiveCMethod:(int)number withData:(NSData *)data
{
      //code here
}

@end
Run Code Online (Sandbox Code Playgroud)

因为C函数在外面@implementation它不能调用类似的方法

[self doSomething]
Run Code Online (Sandbox Code Playgroud)

并且无法访问ivars.

只要回调函数采用 通常类型的userInfocontext类型参数,就可以解决这个问题void*.这可用于将任何Objective-C对象发送到C函数.

示例代码中一样,可以使用常规的Objective-C操作来操作它.

另外请阅读以下答案:在Objective-C类中混合使用C函数

  • C函数不需要在`@ implementation`之外. (30认同)
  • 实际上,@ implementation块中的C函数具有能够直接访问私有和受保护的ivars的独特属性.因此,根据我自己的经验,在相应的实现中放置"属于"类的C函数变成了一种强有力的习惯.我建议你更新你的答案. (22认同)
  • @Bavarious:编译器允许你在`@ implementation`中使用函数,但它仍然不是`@ implementation`的一部分,因为函数不能属于一个类.作为一种风格问题,我把它留在`@ implementation`之外,并推荐其他人做同样的事情,以明确这一点. (12认同)
  • 为了澄清,如果他们可以访问该类的实例,他们将可以访问私有ivars.例如int MyCFunction(MyClass*self,int num,void*data).当你的-MyObjectiveCMethod:withData:objc-method被编译时,这非常类似于幕后的情况. (4认同)
  • c 函数实际上也可以在实现范围内定义,没有人会抱怨。而且,它们在任何情况下都无法在 @implementation 内部或外部访问 self,因为它们不是对象的方法。 (2认同)

dic*_*ciu 26

要从C回调调用Objective-C代码,我会使用类似的东西:

void * refToSelf;
int cCallback()
{
    [refToSelf someMethod:someArg];
}

@implementation SomeClass
- (id) init
{
     self = [super init];
     refToSelf = self;
}
- (void) someMethod:(int) someArg
{
}
Run Code Online (Sandbox Code Playgroud)

  • 只需添加一个:许多回调允许指定"用户数据"; 在这种情况下,对象指针可以用作用户数据(并且您不再需要全局变量refToSelf).可能是您的回调函数支持信息指针中的"用户数据". (8认同)
  • 这是错误的实施.它假设您只有一个ComeClass实例.void*refToSelf; 是一个静态/全局变量.每当你[[SomeClass alloc] init]你的refToSelf将被创建的最后一个实例覆盖.cCallback不会调用正确的SomeClass,而是始终创建最后一个.此外 - 它会在最后一次创建的SomeClass被释放时崩溃(至少在上面的代码中),因为在释放SomeClass时你没有清除refToSelf. (2认同)

Pet*_*sey 8

可以/如何使用Objective-C方法代替此方法?

你不能.

可以/我应该将C函数与Objective-C调用混合使用吗?

是.编写C函数并将其用作CF函数的回调.

如何将C函数与Objective-C方法混合使用?

您可以在上下文结构中设置selfinfo指针.这将被传递给回调.然后,在回调中,将info指针强制转换为id:

MyClass *self = (id)info;
Run Code Online (Sandbox Code Playgroud)

然后,您可以发送self消息.但是,您仍然无法直接访问实例变量,因为C函数位于该@implementation部分之外.你必须把它们作为属性.您可以使用类扩展来执行此操作.(与该文档所说的相反,您不会在内部声明扩展名@implementation,而是在与其相同的文件中,通常在其上方.)


Mar*_*eau 5

我总是发现在这种情况下有用的是在C API之上创建一个Obj-C包装器.实现使用C函数所需的内容,并在其上构建一个Objective-C类(或两个),以便外部世界都能看到.例如,在这样的回调的情况下,您可以创建一个C函数,在其他对象上调用Obj-C委托方法.