gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-30 20:14:25 25 4
gpt4 key购买 nike

前言:我对 iOS 中的 C 集成经验不多,请随时纠正我对此的任何误解。

我有一个项目,它有一个自定义的 2 层“SDK”,都是用 C 编写的。coreSDK 对与 通信的 deviceSDK 进行方法调用>ios 框架 执行硬件操作(即启用相机)或检索设备信息(即 NSDocumentDirectory 的路径)。

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

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

我相信理论上可以使用 ObjC 运行时用纯 C 语言编写 iOS 应用程序,但理想情况下我宁愿不要走那条路,因为我所看到的非常复杂。

示例工作流

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

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


这些是我已经研究过的一些(不是全部)引用资料......


编辑:2016-07-21

为了澄清这个问题,我无法从 (.c) 文件中的 C 方法调用到 (.m) 文件中的 ObjC 方法,或者想出一种替代方法来检索信息,例如(例如)NSDocumentsDirectory在 ObjC(.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 语法的 header 。您的 C 代码中包含的 ObjC 端的任何接口(interface)都需要分解为仅包含有效 C 的自己的 header 。这是一个您需要的演示:

首先,C-only 的头文件和实现文件。

//  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 函数的头文件。 header 本身不包含 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 的接口(interface),因此函数可以使用该类的方法:

//  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];
}

现在,在 main 中或任何您喜欢的地方,您都可以从 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; 并适本地更改所有内容的签名。

关于ios - 如何从纯 C(.c 文件)SDK 到 IOS(obj-C,.m 文件)框架进行通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38489504/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com