围绕Objective-C编写C ++包装器

时间:2011-03-31 18:30:16

标签: c++ objective-c xcode wrapper objective-c++

我想在OS X上的C ++项目中调用和使用Objective-C类。现在是时候开始转向所有Objective-C了,但我们需要在一段时间内完成这项工作。

如何实现这一目标?任何人都可以解释并提供一个例子吗?

4 个答案:

答案 0 :(得分:8)

Objective-C++是C ++的超集,就像Objective-C是C的超集一样。它在OS X上的gcc和clang编译器都支持,并允许你实例化和调用Objective-C对象和放大器。 ; C ++中的方法。只要在C ++模块的实现中隐藏Objective-C头部导入和类型,它就不会感染任何“纯”C ++代码。

.mm是Objective-C ++的默认扩展。 Xcode会自动做正确的事情。

因此,例如,以下C ++类返回自1970年1月1日以来的秒数:

//MyClass.h

class MyClass
{
  public:
    double secondsSince1970();
};

//MyClass.mm

#include "MyClass.h"
#import <Foundation/Foundation.h>

double MyClass::secondsSince1970()
{
  return [[NSDate date] timeIntervalSince1970];
}

//Client.cpp

...
MyClass c;
double seconds = c.secondsSince1970();

您很快就会发现Objective-C ++的编译速度比C ++慢,但正如您在上面所看到的,将其用法与少量桥接类相隔相对容易。

答案 1 :(得分:6)

我认为Phil Jordan确实提出了最好的C ++包装的Obj-C公式。但是,我认为后者,Obj-C包装的C ++更有用。我将在下面解释原因。

使用C ++

包装Objective-C对象

Person.h - Obj-C标题

@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end

PersonImpl.h - C ++标题

namespace people {
    struct PersonImpl;

    class Person
    {
    public:
        Person();
        virtual ~Person();

        std::string name();
        void setName(std::string name);

    private:
        PersonImpl *impl;
    };
}

Person.mm - Obj-C ++实现

#import "Person.h"

#import "PersonImpl.h"

namespace people {
   struct PersonImpl
   {
      Person *wrapped;
   };

   Person::Person() :
   impl(new PersonImpl())
   {
      impl->wrapped = [[Person alloc] init];
   }

   Person::~Person()
   {
      if (impl) {
         [impl->wrapped release]; // You should turn off ARC for this file. 
                                  // -fno-objc-arc in Build Phases->Compile->File options
      }

      delete impl;
   }

   std::string Person::name()
   {
      return std::string([impl->wrapped UTF8String]); 
   }

   void Person::setName(std::string name)
   {
      [impl->wrapped setName:[NSString stringWithUTF8String:name.c_str()]];
   }
}

@implementation Person
@end

使用Objective-C

包装C ++对象

我经常发现真正的问题不是让C ++与Obj-C代码交谈,而是在事情变得丑陋的两者之间来回切换。想象一个对象需要只有C ++的项目,但基本的对象细节填写在Obj-C的土地上。在这种情况下,我用C ++编写对象,然后创建它,以便我可以在Obj-C中与它对话。

Person.h - C ++标题

namespace people
{
   struct PersonImpl;

   class Person
   {
   public:
      Person();
      Person(Person &otherPerson);
      ~Person();
      std:string name;

   private:
      PersonImpl *impl;
   }
}

Person.cpp - C ++实现

namespace people
{
   struct PersonImpl
   {
       // I'll assume something interesting will happen here.
   };

   Person::Person() :
   impl(new PersonImpl())
   {
   }

   Person::Person(Person &otherPerson) :
   impl(new PersonImpl()),
   name(otherPerson.name)
   {
   }

   ~Person()
   {
      delete impl;
   }
}

Person.h - Obj-C标题

@interface Person : NSObject
@property (unsafe_unretained, nonatomic, readonly) void *impl;
@property (copy, nonatomic) NSString *name;
@end

Person.mm - Obj-C ++实现

@interface Person ()
@property (unsafe_unretained, nonatomic) std::shared_ptr<people::Person> impl;
@end

@implementation Person

- (instancetype)init
{
   self = [super init];
   if (self) {
      self.impl = std::shared_ptr<people::Person>(new people::Person());
   }

   return self;
}

- (instancetype)initWithPerson:(void *)person
{
   self = [super init];
   if (self) {
      people::Person *otherPerson = static_cast<people::Person *>(person);
      self.impl = std::shared_ptr<people::Person>(new people::Person(*otherPerson));
   }

   return self;
}

- (void)dealloc
{
   // If you prefer manual memory management
   // delete impl;
}

- (void *)impl
{
   return static_cast<void *>(self.impl.get());
}

- (NSString *)name
{
   return [NSString stringWithUTF8String:self.impl->name.c_str()];
}

- (void)setName:(NSString *)name
{
   self.impl->name = std::string([name UTF8String]);
}

@end

关于空白*

如果你想避免整个项目被.mm文件弄乱,那么你进入C ++领域的第二个你会感到有些痛苦。所以,我们只是说,如果你认为没有必要让你的C ++对象退出,或者用C ++对象重构Obj-C对象,你可以删除该代码。重要的是要注意,第二个是通过Person方法从Obj-C代码中删除void *实例,最好使用复制构造函数或指针创建自己的副本。< / p>

答案 2 :(得分:3)

首先将文件从* .m重命名为* .mm,以便获得Objective-C ++

我没有厌倦这个,所以这是猜测(我今晚会):

因为所有Objective-C ++对象(引用计数)都是通过指针控制的,所以你可以为共享指针编写一个特殊的析构函数。

template<typename T>
struct ObjCDestruct
{
    void operator()(T* obj)
    {
        [obj release];
    }
};

现在你可以将你的Objective-C对象放在boost :: shared_ptr

// FuncFile.M
//
int func()
{
    boost::shared_ptr<MyX, ObjCDestruct<MyX> >  data([[MyX alloc] init]);

    [data.get() doAction1:@"HI"];
}

答案 3 :(得分:0)

查看此问题Calling Objective-C method from C++ method?

你需要有一些objective-c类来包装代码并用C函数公开。