Написание C ++ Wrapper вокруг Objective-C - PullRequest
11 голосов
/ 31 марта 2011

Я хочу вызывать и работать с классами Objective-C из проекта C ++ на OS X. Пора начать двигаться ко всем Objective-C, но нам нужно сделать это через некоторое время.

Как можно достичь этого?Может кто-нибудь пролить свет и привести пример?

Ответы [ 4 ]

8 голосов
/ 31 марта 2011

Objective-C ++ является надмножеством C ++, точно так же, как Objective-C является надмножеством C. Он поддерживается компиляторами gcc и clang в OS X и позволяет создавать и вызывать Objective -C объекты и методы из C ++. Пока вы скрываете импорт и типы заголовков Objective-C в реализации модуля C ++, он не заразит ваш "чистый" код C ++.

.mm является расширением по умолчанию для Objective-C ++. Xcode автоматически сделает правильные вещи.

Так, например, следующий класс C ++ возвращает секунды с 1 января 1970 года:

//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 ++, но, как вы можете видеть выше, относительно легко изолировать его использование от небольшого числа классов-мостов.

6 голосов
/ 22 февраля 2015

Я думаю, что Фил Джордан действительно выдвинул лучшую формулу Obj-C в C ++. Тем не менее, я думаю, что последний, C ++, обернутый Obj-C, более полезен. Я объясню почему ниже.

Обтекание объекта Objective C с 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

Обтекание объекта C ++ с помощью Objective-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

Относительно пустоты *

В тот момент, когда вы вошли в страну C ++, вы почувствовали некоторую боль, если хотите избежать того, чтобы весь ваш проект был завален файлами .mm. Итак, давайте просто скажем, если вы не думаете, что когда-либо необходимо возвращать ваш объект C ++ или воссоздать объект Obj-C с объектом C ++, вы можете удалить этот код. Важно отметить, что после того, как вы удалите экземпляр Person из кода Obj-C с помощью метода void *, вам лучше создать собственную копию с помощью конструктора копирования, иначе указатель станет недействительным.

3 голосов
/ 31 марта 2011

Сначала переименуйте ваши файлы с * .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"];
}
0 голосов
/ 31 марта 2011

Проверить этот вопрос Вызов метода Objective-C из метода C ++?

Вам понадобятся некоторые классы Objective-C, чтобы обернуть код и представить его с функцией C.

...