在 C 结构中包装 Objective-C class 以镜像 class 名称
Wrap an Objective-C class in a C struct to mirror class name
有没有办法将 Objective-C class 包装在 C struct
中,使 struct
名称反映 class 的名称?理想情况下,我希望模仿使用 extern "C"
in C++ as shown here 的行为,而不是必须指向类型 TestObject
的结构成员,在下面的简单程序中演示。
包装 Objective-C class 到 C 结构
testobject.m
#ifndef testobject_h
#define testobject_h
#ifdef __OBJC__
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
typedef struct TestObjectC TestObjectC;
TestObjectC* newTestObject(void);
void TestObject_printHello(TestObjectC *t);
#endif /* testobject_h */
testobject.m
#import <Foundation/Foundation.h>
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
typedef struct TestObject_t
{
TestObject *testObject;
}TestObjectC;
TestObjectC* newTestObject(void)
{
TestObjectC *t = malloc(sizeof(TestObjectC));
t->testObject = [TestObject new];
return t;
}
void TestObject_printHello(TestObjectC* t)
{
[t->testObject printHello];
}
main.c
#include "testobject.h"
int main(int argc, const char * argv[])
{
TestObjectC *t = newTestObject();
TestObject_printHello(t);
return 0;
}
将 C++ class 包装到 C 结构
TestClass.h
#ifndef __TESTCLASS_H
#define __TESTCLASS_H
class TestClass
{
public:
void printHello(void);
};
#endif
TestClass.cc
#include "TestClass.h"
void TestClass::printHello(void)
{
printf("HELLO!\n");
}
MyWrapper.h
#ifndef __MYWRAPPER_H
#define __MYWRAPPER_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct TestClass TestClass;
TestClass* newTestClass();
void TestClass_printHello(TestClass* v);
void deleteTestClass(TestClass* v);
#ifdef __cplusplus
}
#endif
#endif
MyWrapper.cc
#include "TestClass.h"
#include "MyWrapper.h"
extern "C"
{
TestClass* newTestClass()
{
return new TestClass();
}
void TestClass_int_set(TestClass* v, int i)
{
v->printHello();
}
void deleteTestClass(TestClass* v)
{
delete v;
}
}
C程序
#include "MyWrapper.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
struct TestClass* c = newTestClass();
TestClass_printHello(c);
deleteTestClass(c);
}
这里不需要包装器。 ObjC 对象可以毫无问题地通过 C 进行往返,甚至可以支持 ARC。我将稍微更改此处的样式以匹配 CoreFoundation。我将再次编写它以展示在不将调用者暴露给 CoreFoundation 的情况下它会是什么样子。
main.c
int main(int argc, const char * argv[])
{
// "Ref" means pointer. ...Create() means you must Release it.
TestObjectRef t = TestObjectCreate();
// Call your function
TestObjectPrintHello(t);
// And release it.
CFRelease(t);
return 0;
}
testobject.h
#ifndef testobject_h
#define testobject_h
#import <CoreFoundation/CoreFoundation.h>
// Only define the ObjC part in ObjC
#ifdef __OBJC__
#import <Foundation/Foundation.h>
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
// This is the "void *" of CoreFoundation, but it lets the compiler know this
// this is a bridged ObjC object. This is the standard CF way of naming pointer types.
typedef CFTypeRef TestObjectRef;
// This is the standard CF way of naming functions. "Create" means you need to release it.
TestObjectRef TestObjectCreate(void);
// CF functions always start with their class
void TestObjectPrintHello(TestObjectRef t);
#endif /* testobject_h */
testobject.m
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
// ARC is no problem. We just need to tell ARC that we intend to keep an extra retain.
TestObjectRef TestObjectCreate(void) {
return CFBridgingRetain([TestObject new]);
}
// And we can get back to ObjC using `__bridge`
void TestObjectPrintHello(TestObjectRef t) {
[(__bridge TestObject *)t printHello];
}
该解决方案将 CoreFoundation.h 泄露给调用者,并强加了 CF 风格的命名。我碰巧非常喜欢我的系统。但有时我正在处理现有的跨平台 C 系统,而您想隐藏这些细节。因此,如果我试图匹配您示例中的样式,我会这样做:
main.c
int main(int argc, const char * argv[])
{
TestObjectC *t = newTestObject();
TestObject_printHello(t);
TestObject_release(t); // Still need memory management. Can't avoid that.
return 0;
}
testobject.h
#ifndef testobject_h
#define testobject_h
#ifdef __OBJC__
#import <Foundation/Foundation.h>
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
typedef const void TestObjectC; // 'const void *' is more CF-like, but either is fine
TestObjectC* newTestObject(void);
void TestObject_printHello(TestObjectC *t);
void TestObject_release(TestObjectC *t);
#endif /* testobject_h */
testobject.m
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
TestObjectC* newTestObject(void) {
return CFBridgingRetain([TestObject new]);
}
void TestObject_printHello(TestObjectC *t) {
[(__bridge TestObject *)t printHello];
}
void TestObject_release(TestObjectC *t) {
CFRelease(t);
}
有没有办法将 Objective-C class 包装在 C struct
中,使 struct
名称反映 class 的名称?理想情况下,我希望模仿使用 extern "C"
in C++ as shown here 的行为,而不是必须指向类型 TestObject
的结构成员,在下面的简单程序中演示。
包装 Objective-C class 到 C 结构
testobject.m
#ifndef testobject_h
#define testobject_h
#ifdef __OBJC__
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
typedef struct TestObjectC TestObjectC;
TestObjectC* newTestObject(void);
void TestObject_printHello(TestObjectC *t);
#endif /* testobject_h */
testobject.m
#import <Foundation/Foundation.h>
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
typedef struct TestObject_t
{
TestObject *testObject;
}TestObjectC;
TestObjectC* newTestObject(void)
{
TestObjectC *t = malloc(sizeof(TestObjectC));
t->testObject = [TestObject new];
return t;
}
void TestObject_printHello(TestObjectC* t)
{
[t->testObject printHello];
}
main.c
#include "testobject.h"
int main(int argc, const char * argv[])
{
TestObjectC *t = newTestObject();
TestObject_printHello(t);
return 0;
}
将 C++ class 包装到 C 结构
TestClass.h
#ifndef __TESTCLASS_H
#define __TESTCLASS_H
class TestClass
{
public:
void printHello(void);
};
#endif
TestClass.cc
#include "TestClass.h"
void TestClass::printHello(void)
{
printf("HELLO!\n");
}
MyWrapper.h
#ifndef __MYWRAPPER_H
#define __MYWRAPPER_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct TestClass TestClass;
TestClass* newTestClass();
void TestClass_printHello(TestClass* v);
void deleteTestClass(TestClass* v);
#ifdef __cplusplus
}
#endif
#endif
MyWrapper.cc
#include "TestClass.h"
#include "MyWrapper.h"
extern "C"
{
TestClass* newTestClass()
{
return new TestClass();
}
void TestClass_int_set(TestClass* v, int i)
{
v->printHello();
}
void deleteTestClass(TestClass* v)
{
delete v;
}
}
C程序
#include "MyWrapper.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
struct TestClass* c = newTestClass();
TestClass_printHello(c);
deleteTestClass(c);
}
这里不需要包装器。 ObjC 对象可以毫无问题地通过 C 进行往返,甚至可以支持 ARC。我将稍微更改此处的样式以匹配 CoreFoundation。我将再次编写它以展示在不将调用者暴露给 CoreFoundation 的情况下它会是什么样子。
main.c
int main(int argc, const char * argv[])
{
// "Ref" means pointer. ...Create() means you must Release it.
TestObjectRef t = TestObjectCreate();
// Call your function
TestObjectPrintHello(t);
// And release it.
CFRelease(t);
return 0;
}
testobject.h
#ifndef testobject_h
#define testobject_h
#import <CoreFoundation/CoreFoundation.h>
// Only define the ObjC part in ObjC
#ifdef __OBJC__
#import <Foundation/Foundation.h>
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
// This is the "void *" of CoreFoundation, but it lets the compiler know this
// this is a bridged ObjC object. This is the standard CF way of naming pointer types.
typedef CFTypeRef TestObjectRef;
// This is the standard CF way of naming functions. "Create" means you need to release it.
TestObjectRef TestObjectCreate(void);
// CF functions always start with their class
void TestObjectPrintHello(TestObjectRef t);
#endif /* testobject_h */
testobject.m
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
// ARC is no problem. We just need to tell ARC that we intend to keep an extra retain.
TestObjectRef TestObjectCreate(void) {
return CFBridgingRetain([TestObject new]);
}
// And we can get back to ObjC using `__bridge`
void TestObjectPrintHello(TestObjectRef t) {
[(__bridge TestObject *)t printHello];
}
该解决方案将 CoreFoundation.h 泄露给调用者,并强加了 CF 风格的命名。我碰巧非常喜欢我的系统。但有时我正在处理现有的跨平台 C 系统,而您想隐藏这些细节。因此,如果我试图匹配您示例中的样式,我会这样做:
main.c
int main(int argc, const char * argv[])
{
TestObjectC *t = newTestObject();
TestObject_printHello(t);
TestObject_release(t); // Still need memory management. Can't avoid that.
return 0;
}
testobject.h
#ifndef testobject_h
#define testobject_h
#ifdef __OBJC__
#import <Foundation/Foundation.h>
@interface TestObject : NSObject
- (void) printHello;
@end
#endif
typedef const void TestObjectC; // 'const void *' is more CF-like, but either is fine
TestObjectC* newTestObject(void);
void TestObject_printHello(TestObjectC *t);
void TestObject_release(TestObjectC *t);
#endif /* testobject_h */
testobject.m
#import "testobject.h"
@implementation TestObject
- (void)printHello
{
printf("HELLO!\n");
}
@end
TestObjectC* newTestObject(void) {
return CFBridgingRetain([TestObject new]);
}
void TestObject_printHello(TestObjectC *t) {
[(__bridge TestObject *)t printHello];
}
void TestObject_release(TestObjectC *t) {
CFRelease(t);
}