如何从纯C(.c文件)SDK到IOS(obj-C,.m文件)框架进行通信?

濑津四郎

前言:我几乎没有在iOS中进行C集成的经验,请随时纠正我对此的任何误解。

我有一个项目,该项目具有一个用C编写的自定义2层“ SDK” 。coreSDKdeviceSDK进行方法调用,该设备ios框架进行通信以执行硬件操作(即启用摄像头)或检索设备信息(即。 NSDocumentDirectory的路径)。

不幸的是,由于基础结构的缘故,两个SDK文件扩展名都使用(.h)和(.c),并且不能像某些来源建议的那样更改为(.m)。根据我所读的内容,我可以为ObjC方法创建C回调,但这仅对单例才真正可行,并且C回调需要在(.m)文件的范围内。

我尝试在ObjC中创建包装类,以便它具有deviceSDK调用的C回调,但是当包含该(.m)的标头(.h)时,编译器似乎崩溃了。如果我的理解是正确的,那是因为C编译器无法解释(.m)中包含的ObjC语言。

我认为从理论上讲可以用ObjC运行时用纯C语言编写iOS应用程序,但理想情况下不希望这样做,因为我所见过的事情太复杂了。

工作流程示例

  1. ViewController.m方法调用coreSDK方法(.c)
  2. deviceSDK方法(.c)的coreSDK方法调用
  3. deviceSDK需要检索(例如)NSDocumentDirectory(或启用摄像头)

我怎样才能做到这一点?
代码示例将是最全面的,值得赞赏。
谢谢!


这些是我已经研究过的一些(不是全部)参考书...


编辑:2016-07-21

为了澄清这个问题,我无法从(.c)文件中的C方法调用(.m)文件中的ObjC方法,或者想出一种替代方法来检索信息,例如(例如)ObjC中的NSDocumentsDirectory( .m文件)并传递回(.c)文件中的C。

示例代码:当然,这是不正确的,但是它符合我的期望或我希望实现的目标。

//GPS.h
#include "GPSWrapper.h"
STATUS_Code GPSInitialize(void);
//GPS.c
#include "GPS.h"
STATUS_Code GPSInitialize(void) {
  GPS_cCallback();
}
//GPSWrapper.h
#import <Foundation/Foundation.h>
@interface GPSWrapper: NSObject
- (void) testObjC;
@end
//GPSWrapper.m
#import "GPSWrapper.h"
static id refToSelf = nil;
@implementation GPSWrapper
  - (void) testObjC {
    // just an example of a ObjC method call
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSLog(documentsDirectory);
  }
@end

static void GPS_cCallback() {
  [refToSelf testObjC];
}
脚本

#include "GPSWrapper.h"您示例中的这一行就是问题所在。您不能在要编译为C的文件中包含具有ObjC语法的标头。C语言中包含的与ObjC端的任何接口都必须分解为仅包含有效C的标头。您需要的演示:

首先,仅C的东西的标头和实现文件。

//  CUtils.h
//  OCFromC

#ifndef CUtils_h
#define CUtils_h

#include <stdio.h>

void doThatThingYouDo();

void doThatThingWithThisObject(const void * objRef);

#endif /* CUtils_h */

//  CUtils.c
//  OCFromC

// Proof that this is being compiled without ObjC
#ifdef __OBJC__
#error "Compile this as C, please."
#endif

#include "CUtils.h"
#include "StringCounterCInterface.h"

void doThatThingYouDo()
{
    printf("%zu\n", numBytesInUTF32("Calliope"));
}

void doThatThingWithThisObject(const void * objRef)
{
    size_t len = numBytesInUTF32WithRef(objRef, "Calliope");
    printf("%zu\n", len);
}

注意第二个功能;如果需要,您可以在C语言环境中传递对象引用,只要将其隐藏在void *。中即可。对于内存管理,还需要进行一些强制转换。下面的更多内容。

这是我们将要使用的令人兴奋的ObjC类:

//  StringCounter.h
//  OCFromC

#import <Foundation/Foundation.h>

@interface StringCounter : NSObject

- (size_t)lengthOfBytesInUTF32:(const char *)s;

@end

 //  StringCounter.m
 //  OCFromC

 #import "StringCounter.h"

 @implementation StringCounter

 - (size_t)lengthOfBytesInUTF32:(const char *)s
 {
     NSString * string = [NSString stringWithUTF8String:s];
     return [string lengthOfBytesUsingEncoding:NSUTF32StringEncoding];
 }

 @end

现在,这是重要的部分。这是一个声明C函数的头文件。标头本身不包含ObjC,因此可以将其包含在CUtils.c中,如您在上面看到的那样。

//  StringCounterCInterface.h
//  OCFromC

#ifndef StringCounterCInterface_h
#define StringCounterCInterface_h

// Get size_t definition
#import <stddef.h>

size_t numBytesInUTF32(const char * s);
size_t numBytesInUTF32WithRef(const void * scRef, const char *s);

#endif /* StringCounterCInterface_h */

这是连接点。它的实现文件被编译为ObjC,并且包含刚刚声明的那些函数的定义。此文件导入的接口StringCounter,因此函数可以使用该类中的方法:

//  StringCounterCInterface.m
//  OCFromC

#ifndef __OBJC__
#error "Must compile as ObjC"
#endif

#import "StringCounterCInterface.h"
#import "StringCounter.h"

size_t numBytesInUTF32(const char * s)
{
    StringCounter * sc = [StringCounter new];
    // Or, use some "default" object in static storage here
    return [sc lengthOfBytesInUTF32:s];
}

size_t numBytesInUTF32WithRef(const void * objRef, const char * s)
{
    StringCounter * sc = (__bridge_transfer StringCounter *)objRef;
    return [sc lengthOfBytesInUTF32:s];
}

现在,在主要或您喜欢的任何地方,您都可以通过CUtils行使这些功能:

//  main.m
//  OCFromC

#import <Foundation/Foundation.h>
#import "StringCounter.h"
#import "CUtils.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        doThatThing();
        // Create an object reference
        StringCounter * sc = [StringCounter new];
        // Tell ARC that I know this is dangerous, trust me,
        // pass this reference along.
        const void * scRef = (__bridge_retained void *)sc;
        doThatThingWithThisObject(scRef);
    }
    return 0;
}

通过桥接强制转换以及StringCounterCInterface.m中的对应转换,可以将ObjC对象移动通过ARC无法通过的区域。在将对象隐藏在中之前void *,它会增加对象的保留计数,因此在将__bridge_transfer其返回到ObjC土地之前,不会意外释放该对象。

最后一点:如果要在C中大量传递对象引用,则可以考虑typedef void * StringCounterRef;适当地和更改所有内容的签名。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何将C ++头文件从静态库导入到Obj-C中?

来自分类Dev

在纯C中解析.pcap文件

来自分类Dev

如何使用Objective-C从纯文本远程文件中读取内容

来自分类Dev

如何以纯Android Studio方式编译我的C ++库(无需自行指定任何.mk文件)

来自分类Dev

纯文本文件或加密文件(C编程)

来自分类Dev

C stderr到文件

来自分类Dev

如何仅在纯c中迭代直接设置的枚举值?

来自分类Dev

如何包装std :: vector以在纯C中使用

来自分类Dev

如何在纯C#中使用PL / SQL?

来自分类Dev

为什么C ++ OBJ文件很重要?

来自分类Dev

在C ++中从.obj文件读取整数

来自分类Dev

在 FireMonkey 中链接 C Obj 文件

来自分类Dev

如何从Visual C ++的.obj文件构建静态和动态库?

来自分类Dev

如何在obj文件中使用面值(opengl c ++)

来自分类Dev

iOS-在Watch Extension中添加Obj-C文件导致错误

来自分类Dev

什么是.c.obj / .cpp.obj文件?

来自分类Dev

将Swift框架导入到Obj-C

来自分类Dev

(C / C ++)libjpeg,缺少“ Release.obj”文件

来自分类Dev

如何简单地将 ESQL/C 文件转换为 C 文件?(嵌入式 SQL/C 文件到 C 文件)?

来自分类Dev

BMP字符数组到文件C / C ++

来自分类Dev

使用GDB进行纯C程序的远程调试

来自分类Dev

如何将参数从UWP应用传递到纯C ++控制台应用?

来自分类Dev

Cython:纯C循环优化

来自分类Dev

C ++纯虚拟多重继承?

来自分类Dev

C ++类模板或纯虚拟

来自分类Dev

纯C.Dll出口

来自分类Dev

纯C.Dll出口

来自分类Dev

C语言中的纯字符

来自分类Dev

来自纯 C++ 的 NSUserNotification