Я думаю, что Фил Джордан действительно выдвинул лучшую формулу 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 *
, вам лучше создать собственную копию с помощью конструктора копирования, иначе указатель станет недействительным.