Have C++ class manage life of Objective-C class? - c++

Here is what I am not sure about:
I have a c++ class that will create and own an obj-C object and very simply, when that C++ class is constructed I call:
this->objCObject = [ThatObject new];
But how do I deal with destroying the ObjC object in ~MyCPPClass() ? Under ARC there is no retain/release.
Thanks

You could disable ARC for the specific file that contains your CPP class. That will give you the freedom to use retain/release in your CPP class.
If you have multiple cases that need the same trick, you could look at the shared_ptr for Objective-C objects

Related

How to pass a callback function from C++ to Objective-C

I don't want to use NSNotification because it is so messing up internally. Is it a way to pass a callback function from C++ to Objective-C++, and let Objective-C call it?
The problem is that I don't know how to pass a function written in C++ to Objective-C++, and how could I use that callback in Objective-C++? Is it a pointer?
I know I can mix them up but my class has to be a C++ class because it inherits some C++ classes.
You're not 100% specific as to the exact use case you're trying to cover here, but I'm going to set out a scenario where this kind of situation occurs, and then show you how to solve it. I hope that will cover your problem too.
So I'm going to assume you have an Objective-C class MyClass with its interface declared in MyClass.h:
#interface MyClass : NSObject
- (void)someMethod;
- (void)otherMethodWhichShouldTakeACallback:?????;
#end
You now have a C++ class MyCPPClass, declared in MyCPPClass.hpp on which you want to pass memberFunction as the callback argument to the otherMethod on MyClass:
class MyCPPClass : public MyBase
{
void memberFunction();
};
First, we need to figure out the method signature on MyClass. The modern way for callbacks in Objective-C is with Blocks. Blocks work pretty well with Objective-C++, so let's go with that and modify MyClass.h with the following line:
- (void)otherMethodWithBlock:(void(^)(void))callbackBlock;
The calling code will need to reside in an Objective-C++ compilation unit (caller.mm):
void callOtherMemberWithCPP(MyCPPClass* cpp_obj, MyClass* objc_obj)
{
[objc_obj otherMethodWithBlock:^{
cpp_obj->memberFunction();
}];
}
Note that this does not deal with object lifetimes. If you're managing lifetimes on the C++ side with std::shared_ptr, you can use that in your Objective-C++ code too, in which case we might end up with something like:
void callOtherMemberWithCPP(std::shared_ptr<MyCPPClass> cpp_obj, MyClass* objc_obj)
{
[objc_obj otherMethodWithBlock:^{
cpp_obj->memberFunction();
}];
}
In this case, the C++ object will only have its reference count decremented when the Objective-C class is done with the block.
For completeness, the other way to do this would be to use C function pointer syntax. In this case, you would need to declare the Objective-C method along these lines:
- (void)otherMethodWithCallback:(void(*)(void*))callback object:(void*)opaqueCallbackArgument;
And the C++ class's method call would need to be wrapped in a free function or static member function:
void memberFunctionCallback(void* opaque_object)
{
MyCPPClass* object = static_cast<MyCPPClass*>(opaque_object);
object->memberFunction
}
…and then call the Objective-C method like this:
[objc_obj otherMethodWithCallback:memberFunctionCallback object:cpp_obj];
Making this version work nicely with automatic lifetime mechanisms such as shared_ptr is a lot more tricky though.

Mixing C++ and Objective-C

I am using C++ as the app backbone and Objective-C for the GUI, that's fine.
But when it comes to mixing those code together in Objective-C++ (.mm file), I have got a few question:
1. Can I mix STL containers with Objective-C or Cocos2D objects?
E.g. In Objective-C header, can I do the following?
#include <vector>
#include <boost\shared_ptr.hpp>
#interface MyClass : NSObject {
std::vector<boost::shared_ptr<CCSprite> > m_spriteList;
}
And then in the .mm file, I want to do
CCSprite* newSprite = [/* cocos2d stuff here... */];
m_spriteList.push_back(newSprite);
Is the above code valid? It certainly is in C++, but I am not sure when mixing C++ and Objective-C and Cocos2D.
2. Memory management using C++ smart pointer object in Objective-C?
When I try to use the C++ code in Objective-C, I want to declare a C++ object as a member variable in the Objective-C header file.
Say I have a C++ class declared in the test.h header:
Test{
};
In Objective-C header file, I want to do
#include "test.h"
#incude <boost/scoped_ptr.hpp>
#include <vector>
#interface MyClass : NSObject {
Test* m_testObjectPtr; // (1)
boost::scoped_ptr<Test> m_testOjbSmartPtr; // (2)
}
In the above code, is (2) okay? Can I use smart pointers in Objective-C just like in C++ code? And can I assume the Test class destructor will be called when the MyClass object is destroyed?
Or if (2) is not okay in Objective-C++, is (1) okay? Would I need to manually call
delete m_testObjectPtr in dealloc?
You can use smart pointer only on c++ classes. if you use then on objective-c classes you will either get compile error or crash somewhere.
You can also use containers with pointers of objective-c classes like
std::vector<CCSprite *> spriteList;
just make sure you retain them when you insert them to list and release them when you remove them.
In both cases, you can make a smart pointer of your own that calls retain and release in constructor/destruct/copy like needed and then don't worry about retain release.
Also destructor for member c++ objects will be called automatically when the object is deallocated.
An example of an objective c wrapper would be
template<typename T>
struct shared_objc_object
{
T *Object;
shared_objc_object : Object(nil) { }
shared_objc_object(T *Object) : Object([Object retain]) { }
shared_objc_object(shared_objc_object &other) :
Object([other.Object retain]) { }
~shared_objc_object() { [Object release]; }
shared_objc_object &operator =(shared_objc_object &other)
{
[Object release];
Object = [other.Object retain];
}
}
And you can use
std::vector<shared_objc_object<CCSprite *>> spriteList;
spriteList.push_back(some_sprite);
and don't care about retain/release
There are some issues you'll want to be aware of. C++ classes do not enjoy the same scope based lifetime you might be used to when made into class members of Objective-C++ objects. When alloc/initing, the constructor won't be called, and when releasing, the destructor won't be called, unless you carefully use in place new/delete or hold on to a pointer and explicitly manage it with new/delete.
Also, if the Objective-C++ header needs to be shared with Objective-C files, you cannot use any C++ constructs at all. Both problems can be mitigated by hiding all C++ members using the pimpl pattern.
Can I mix STL containers with Objective-C or Cocos2D objects?
Yes, since Objective-C objects are just pointers to structs, you can store them easily in STL containers and even forward declare the type and pass it into pure C++ code. (Note, the C++ code can't really do much with the pointer without tricky and brittle code, but you can always pass the pointer back into Objective-C code later to get useful work done.)
Memory management using C++ smart pointer object in Objective-C?
You can use smart pointers to manage the lifetime of your Objective-C objects, but you will need to be careful that they do not call delete (the default behavior for most C++ smart pointers). With shared_ptr from C++11 or boost, you can provide a custom deleter; though now you have two reference counting systems. You can instead use boost::intrusive_ptr to skip that extra overhead and use Objective-C's reference counting directly.

Trouble with adding C++ objects to Objective C collections (NSSet)

I'm busy implementing ZXing with a QRCodeReader into my project.
QRCodeReader is mainly C++ and my project objective-C.
I have managed to implement it properly so I can use the QRCodeReader objects into my objective-C implementation (.mm file).
But now I need to pass this C++ object to the zxWidController.reader property.
This means I will have to set the C++ object into an NSSet Object.
QRCodeReader* qrcodeReader = new QRCodeReader();
NSSet *readers = [[NSSet alloc ] init];
[readers setByAddingObject:(id)qrcodeReader];
widController.readers = readers;
[readers release];
The code above does the trick. I casted the C++ object to (id) and now it compiles properly. But is this the proper way to do it?
Is this manner of programming the proper way to do this?
Are there any other / better ways to achieve my goal?
A C++ type is not an Objective C type. You cannot send it messages, in particular retain and release, which NSSet does. There's an Objective C type of the same name that you want to use. (I'll update my other answer).
The code above does the trick. I casted the C++ object to (id) and now
it compiles properly. But is this the proper way to do it?
No. You can't just make an arbitrary pointer into a valid Objective-C object pointer by casting it to id.
Is this manner of programming the proper way to do this?
Again, no.
Are there any other / better ways to achieve my goal?
You can try any of the following:
Redefine your zxWidController class to take a pointer to a C++ object instead of an Obj-C object.
Wrap qrcodeReader in a NSValue.
Take a look at NSPointerArray as a replacement for NSSet. Definitely read the docs before you try to use it -- you have to configure it's memory management policies to do the right thing for the type of pointer you're storing.
Minor nitpick: Forgetting for a moment about the fact that qrcodeReader points to a C++ object, it seems silly to create an empty set just so that you can add an object to it. If you were going to use an Obj-C set, then either create it using +setWithObject: or use NSMutableSet instead.

How should I create classes in ATL project?

I'm writing an ATL project and I wonder how should I create classes here.
Right now I have one class created by Add/Class/ATL Simple Object. I want to divide it to smaller classes but method from this classes should use CComPtr and have CComPtr as an argument. I can't create 'simple' c++ class because I don't have CComPtr there.
Should I create ATL classes by ATL Simple Object Wizard and then use interface for this class to call methods. Like here:
CComPtr<ITestAtlClass> tptr;
tptr.CoCreateInstance(CLSID_TestAtlClass);
tptr->test();
And should I add all public methods by Class View/ITestAtlClass/Add/Add Method?
What about constructors? Do I must initialize my class only by properties (and add them by Class View/ITestAtlClass/Add/Add Property)? And pass every com object by IUnknown interface?
Can somebody tell me how it should be done in ATL project. I will use this smaller classes internally (nobody will create this classes outside my DLL) just to make my code more readable.
I don't understand your comment that you can't use CComPtr from a simple C++ class. Can you please clarify?
I see two strategies:
build a clean C++ object model that solves the problem, and then wrap it in a thin facade layer of one or more COM objects
Use ATL classes throughout, and use CComObject<> and derivatives to instantiate and maintain these without the overhead of CoCreateInstance and the limitations of only using public interfaces.
The first one is usually much nicer, but if you're building a data-heavy object model, the second can be a useful technique.
If you have an ATL COM class called CVehicle, that derives from CComObjectRootEx<> and friends, you can instantiate it like so;
CComObject<CVehicle>* vehicle = NULL;
CComObject<CVehicle>::CreateInstance(&vehicle);
vehicle->AddRef();
// To get at any of its interfaces, use:
CComPtr<ICar> car = 0;
vehicle->QueryInterface(&car);
// And to delete object, use:
vehicle->Release();
There's also variations on CComObject<>, e.g. CComObjectStack<> that use different allocation and reference counting strategies.
As you can see, this is pretty messy. If you can explain what you mean by your comment on not being able to use CComPtr, maybe I can expand on that.

Using a VB.NET DLL file in C++ - class is abstract

I created a VB.NET DLL file which I am using in an unmanaged C++ project.
When I try to create an object of the class, I am getting an error:
cannot instantiate abstract class
Why would my class be abstract? How can I modify it so that it won't be abstract?
That's not how it works, you have to write COM code in C++ to use it. Take a good look at the #import directive and the smart pointers it creates.