Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从纯C(.C文件)SDK到IOS(obj-C,.m文件)框架进行通信?_Ios_Objective C_C_Iphone - Fatal编程技术网

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

如何从纯C(.C文件)SDK到IOS(obj-C,.m文件)框架进行通信?,ios,objective-c,c,iphone,Ios,Objective C,C,Iphone,前言:我对iOS中的C集成几乎没有经验,请随时纠正我对此的任何误解 我有一个项目,它有一个自定义的两层“SDK”,都是用C编写的。coreSDK对deviceSDK进行方法调用,deviceSDK与ios框架进行通信,以执行硬件操作(即启用摄像头)或检索设备信息(即NSDocumentDirectory的路径) 不幸的是,由于基础设施的原因,SDK文件扩展名都使用(.h)和(.c),并且不能像某些源建议的那样更改为(.m)。根据我读到的内容,我可以创建ObjC方法的C回调,但这只适用于单例,并且

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

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

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

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

我相信从理论上讲,用纯C和ObjC运行时编写iOS应用程序是可能的,但在理想情况下,我宁愿不走这条路,因为我所看到的是荒谬的复杂

工作流示例

  • ViewController.m方法调用coreSDK方法(.c)
  • coreSDK方法调用deviceSDK方法(.c)
  • deviceSDK需要检索(例如)NSDocumentDirectory(或启用摄像头)
  • 我如何才能做到这一点?
    代码示例将是最全面和最受欢迎的。
    谢谢


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


    编辑:2016-07-21 为了澄清这个问题,我在从(.C)文件中的C方法调用(.m)文件中的ObjC方法时遇到了问题,或者在寻找另一种方法来检索信息时遇到了问题,例如,在ObjC(.m)文件中检索NSDocumentsDirectory并将其传回(.C)文件中的C

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

    //GPS.h
    #include "GPSWrapper.h"
    STATUS_Code GPSInitialize(void);
    
    这一行
    #在您的示例中包括“GPSWrapper.h”
    就是问题所在。在编译为C的文件中,不能包含具有ObjC语法的头文件。C代码中包含的ObjC端的任何接口都需要拆分为只包含有效C的头文件。下面是您需要的演示:

    首先,头文件和实现文件,用于C-only文件

    //  CUtils.h
    //  OCFromC
    
    #ifndef CUtils_h
    #define CUtils_h
    
    #include <stdio.h>
    
    void doThatThingYouDo();
    
    void doThatThingWithThisObject(const void * objRef);
    
    #endif /* CUtils_h */
    
    注意第二个函数;如果需要,可以在C语言中传递对象引用,只要它被隐藏在
    void*
    中。内存管理还需要进行一些转换。下面将详细介绍

    这是我们将使用的激动人心的ObjC类:

    //  StringCounter.h
    //  OCFromC
    
    #import <Foundation/Foundation.h>
    
    @interface StringCounter : NSObject
    
    - (size_t)lengthOfBytesInUTF32:(const char *)s;
    
    @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 */
    
    现在,无论是在主要场合还是在任何你喜欢的场合,你都可以从表皮上锻炼这些功能:

    //  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;
    }
    
    //main.m
    //OCFromC
    #进口
    #导入“StringCounter.h”
    #导入“CUtils.h”
    int main(int argc,const char*argv[]{
    @自动释放池{
    doThatThing();
    //创建对象引用
    StringCounter*sc=[StringCounter新建];
    //告诉ARC我知道这很危险相信我,
    //把这个参考资料传下去。
    const void*scRef=(uu桥u保留的void*)sc;
    使用此对象进行任何操作(scRef);
    }
    返回0;
    }
    
    桥接投射与StringCounterCInterface.m中的对应项一起,允许您在圆弧无法到达的区域移动ObjC对象。它会在对象隐藏在
    void*
    中之前碰撞对象的保留计数,以便在您可以
    \uuuu bridge\u将其传输回ObjC land之前不会意外释放它


    最后一个注释:如果你要通过C中的对象引用很多,你可以考虑做<代码> TyPulfValue* StringCounterRef;<代码>并适当地更改所有内容的签名。

    OSX和iOS音频程序充满了有益的示例:虽然整个程序都是用Obj-C编写的,但关键的音频处理代码必须“精简”到纯C。请参阅所谓的“核心音频”标签。这没有真正意义;从ObjC中,C是100%可用的。是的,这是单向的:您不能在编译为C的文件中包含ObjC头,也不能发送ObjC消息,但在ObjC类或编译为ObjC的文件中的C函数中为您的必选项C函数提供包装应该没有问题。你能不能提供一个你正在做的事情的最小演示,并准确地解释它是如何失败的?你可以从Objective-C调用C方法,这没什么大不了的。不要重命名,只需包含.c和.h文件,然后从那里开始。问题不在于从ObjC调用C,而在于从(.C)文件中的C方法调用(.m)文件中的ObjC。我用额外的细节和测试代码样本更新了我的问题,或者我的期望值是什么。这是我问题的一个漂亮答案。虽然有一个稍微相关的问题,但我注意到这里我们返回的是字节大小的size\u t,但在处理a时,我必须将objc中字符串的返回类型定义为
    const char*
    to c(知道c字符串是字符数组)。我花了一段时间才弄明白这一点,但是在这个场景中我如何定义其他常见的数据类型呢?我选择了
    size\u t
    ,这样C端就不必得到
    NSUInteger
    的定义,这是
    lengthofBytes susingCodeing:
    的实际返回类型。严格说来,它们不是一样的,但实际上是一样大小的
    //  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);
    }
    
    //  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
    
    //  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 */
    
    //  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.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;
    }