Mixing Objective C++ and C++ in a bi-directional way - c++

Suppose I have two objective c++ objects that each wrap a native c++ object given:
A, B = objective c++ object types
Acpp, Bcpp = c++ object types
In B.mm
#import "Bcpp.h"
#import "B.h"
#interface B ()
{
Bcpp myBcpp; // declare instance c++ variable of type Bcpp
}
#end
In A.mm
#import "Acpp.h"
#import "A.h"
#interface A ()
{
Acpp myAcpp; // declare instance c++ variable of type Acpp
}
#end
#implementation A
// method to return an instance of B from an instance of A (self)
- (B)GetBfromA
{
Bcpp *bfroma = myAcpp.GetBfromA(); // return c++ object
// How do i find the objective C++ object B from its wrapped c++ instance bfroma?
}
#end
The reason for doing this is we have a mature c++ data structure and we wish to wrap it with objective c++ objects. Is the the best way? And if it is, how do we solve the reverse mapping problem?
EDIT: Thank you to the early responders but I have a more tricky situation that I implied above. Suppose the function GetBFromA() returns an instance of Bcpp that had already been declared (as an instance variable of an instance of B). So I am holding a pointer to a Bcpp object that is itself an instance variable of an objective C++ object of type B. How do I find the instance of B from the instance of Bcpp?

What you probably need to do is to be able to create a B from a Bcpp. So B will need to be amended to have an -initWithBcpp: method:
- (id)initWithBcpp:(Bcpp*)bcpp
{
self = [super init];
if (self != nil)
{
myBcpp = *bcpp;
}
return self;
}
Then, in GetBFromA, you'll need to create a B from the Bcpp*:
- (B*)GetBfromA
{
Bcpp *bfroma = myAcpp.GetBfromA(); // return c++ object
B* result = [[B alloc] initWithBcpp:bfroma];
return result;
}

Related

Delegate issue between Objective-C and Swift

I'm just about to get into the basics of Swift, Objective-C & C++. I'm trying to build a bridge between Objective-C & Swift & set up a suitable delegate (MyDelegate).
The code below is working quite fine but I got some problems calling the Swift function callbackInteger() from a static function like:
MyFile.mm:
static void test() {
// how to call callbackInteger?
}
MyFile.mm:
- (void)callbackToSwift:(int)testInteger {
if (self.delegate != nil) {
[self.delegate callbackInteger: testInteger];
}
}
MyDelegate.h:
#protocol MyDelegate <NSObject>
- (void) callbackInteger: (int) testInteger;
#end
ViewController.swift:
class ViewController: UIViewController, MyDelegate {
func callbackInteger(_ testInteger: Int) {
print("testInteger: \(testInteger)");
}
}
Note: I really have no idea how to achieve a call to the callbackInteger function using the delegate call.
A protocol is nothing more that a set of requirements (methods) that a class has to implement. We say that a class conforms to a protocol.
So in your static function test(), you can't call the method of the protocol if you don't have an instance/object around (here a ViewController). A working way (but not necessary a beautiful one) would be to store somewhere (as a global variable for example) an instance of ViewController in order to reuse it in the function.
Something like this :
// Top of your file
#import <Foundation/Foundation.h>
// other headers...
id<MyDelegate> globalDelegate;
static void test() {
[globalDelegate callbackInteger:42];
}
// rest of your file
There are plenty of resources about protocols and the delegation pattern like this guide from Apple. Read carefully how they use it in Cocoa & Cocoa Touch.

How to access Swift-objects from a c++ class?

I want to change the properties of some objects (Labels, Buttons..), I created using the Storyboard out of c++-code. So I need a way of running ViewController-class-internal methods.
Is there any proper way to do this? Is there another possibility?
I've tried using callbacks, but there is always this barrier between global and internal in the ViewController-class. Thanks in advance!
EDIT:
Since I don't know how to access a swift class out of c++ code, i cannot give any proper examples, but I thought of something like this (pseudo code):
In c++:
int main(){
say_hello();
}
and in Swift:
class ViewController: NSViewController {
#IBOutlet weak var label: NSTextField!
func say_hello(){
label.stringValue = "Hello"
}
}
Here is an oversimplified example of how this could be done using an Objective-C++ wrapper, as suggested by Richard. Memory management and thread safety aspects, and many other things, are not addressed here. In this example there is a 1-to-1 relationship between Swift and C++ class instances. Also, Swift object pointers are used as identifiers to decide which Swift object should receive a notification. This is kind of dangerous, see comments in the code below. Using more sophisticated data structures in the Objective-C++ wrapper to maintain a connection between Swift and C++ objects, one could easily work around this danger and support relationships other than 1-to-1.
First of all, here is a C++ class that triggers changes in Swift code:
typedef void (*cb_t)(const char *, void *);
class MyClassCPP {
public:
MyClassCPP(cb_t callBack, void * p) : myCallBack(callBack), clientPtr(p) {}
void doWork(); // perform some work and invoke the callback
private:
cb_t myCallBack;
void * clientPtr;
};
void MyClassCPP::doWork() {
myCallBack("C++ code at work...", clientPtr);
}
Here is an Objective-C++ wrapper interface that should be made visible to Swift code via the bridging header, directly or indirectly. Please note that it does not reference any C++ types.
#class SwiftClass; // forward declaration
// can't include *-Swift.h in a header
#interface OCWrapper : NSObject
-(instancetype)init:(SwiftClass * )sc;
-(void)requestWorkFromCPP;
#end
And here is the wrapper implementation. It does reference C++ types. We cannot provide a Swift global function as a callback to C++ code, but we can provide an Objective-C++ global function for this purpose.
// Extension that deals with C++ specifics that can't be visible to Swift
#interface OCWrapper ()
{
MyClassCPP * myClassCPP;
}
#end
void callBack(const char * msg, void * swiftClient)
{
// Danger: what if swiftClient does not point to a SwiftClass instance?
[(__bridge SwiftClass*)swiftClient sayHello:
[[NSString alloc] initWithBytes: msg length:strlen(msg)
encoding:NSASCIIStringEncoding]];
}
#implementation OCWrapper
-(instancetype)init:(SwiftClass * )sc
{
myClassCPP = new MyClassCPP(callBack, (__bridge void*)sc);
return self;
}
-(void)requestWorkFromCPP{
myClassCPP->doWork();
}
#end
The above should be in an Objective-C++ file. Create an Objective-C file and then rename it to have the .mm extension. You will also need to include the *-Swift.h header, so Objective-C++ can use Swift types.
Finally, here is some Swift code that uses the C++ code via the Objective-C++ wrapper:
// This is like your Swift view controller
class SwiftClass : NSObject
{
var label = "[Empty]"
var name : String;
init(name : String) {
self.name = name
}
func sayHello(greeting : String) {
label = "SwiftClass named " + name + " received greeting: " + greeting
}
}
...
let sc = SwiftClass( name : "Zero")
let ocWrapper = OCWrapper(sc)
let sc1 = SwiftClass( name : "One" )
let ocWrapper1 = OCWrapper(sc1)
ocWrapper1.requestWorkFromCPP()
print("The label value from C++: \(sc1.label)")
ocWrapper.requestWorkFromCPP()
print("The label value from C++: \(sc.label)")
...

Lua/Luabind: Objects constructed by objects remain allocated

I have a simple Lua script
function TestFunction(Id)
local Factory = TestParent();
local ChildDirect = TestChild("DirectCall");
local ChildFactory1 = Factory:CreateChild("Factory1");
local ChildFactory2 = Factory:CreateChild("Factory2");
result = Ret()
return result
end
that uses two C++ exposed objects (trough luabind)
void TestParent::RegisterToLua(lua_State* lua)
{
// Export our class with LuaBind
luabind::module(lua)
[
luabind::class_<TestParent>("TestParent")
.def(luabind::constructor<>())
.def("CreateChild", &TestParent::CreateChild)
];
}
void TestChild::RegisterToLua(lua_State* lua)
{
// Export our class with LuaBind
luabind::module(lua)
[
luabind::class_<TestChild>("TestChild")
.def(luabind::constructor<std::string>())
.def("GetValue", &TestChild::GetValue)
];
}
I call the function
luabind::object obj = luabind::call_function< luabind::object >(LuaState, "TestFunction", IdParam);
if ( obj.is_valid() )
{
....
}
lua_gc(LuaState, LUA_GCCOLLECT, 0);
During lua_gc call only Factory and ChildDirect objects are destroyed. ChildFactory1 and ChildFactory2 remains allocated. The lua stack remains balanced (has same value - 5 - some tables ) after the luabind::call_function.
What is the problem ? The objects created by Factory remain somehow referenced ? By who ?
CreateChild body is
TestChild* TestParent::CreateChild(std::string strname)
{
return new TestChild(strname);
}
The ownership of the new constructed object should be taken by lua object and destroyed if ChildFactory1 or ChildFactory2 is nil-ed or out of scope.
adopt: Used to transfer ownership across language boundaries.
module(L)
[
def("create", &create, adopt(result))
];
You should return a smart pointer (i.e. a boost::shared_ptr) from your factory.
see: LuaBind Documentation # smart pointer
and a discussion in the LuaBridge docu

Can I use a C++ Class Instance as an Objective-C++ id?

In connecting my C++ data model to my Cocoa table column UI, I'm wondering if I can provide the a C++ class instance at the id (identifier) to initWithIdentifier
// what magic needs to occur to create an id from a CPP class?
id someIDMadeFromAClassInstance = a_ptr_to_a_cpp_class_instance;
NSTableColumn *col = [[NSTableColumn alloc] initWithIdentifier:someIDMadeFromAClassInstance"];
The whole point of this is so that when the NSTable's datasource method objectValueForTableColumn gets called, I can retrieve the id and somehow convert if back to a valid C++ class instance:
id columnIdentifer = [aTableColumn identifier];
MyCPPClass* pAValidClass = [someMagicOnTheID columnIdentifer];
pAValidClass->AClassMethod();
I'm guessing there's a more traditional method of doing this, but I wanted to simplify the connection between the Cocoa UI and a pure C++ model.
A C++ object pointer cannot be stored in an id type variable. In Objective-C, id is a pointer to an Objective-C object of unknown type. Since a C++ object is not an Objective-C object, it is not safe to store the pointer to a C++ object in an id.
The solution is to add a property to your Objective-C class that will store a C++ object pointer. If you must use an id, you could make an Objective-C class that wraps a property that stores the C++ object pointer, for example:
#interface MyCPPClassWrapper : NSObject
#property (nonatomic, assign) MyCPPClass *myCPPClass;
#end
// ...
MyCPPClassWrapper *wrapper = [[MyCPPClassWrapper alloc] initWithMyCPPClass:myCPPClass];
// Hand wrapper off to your NSTable
Take a look at NSValue as well. It provides a storage mechanism for C-style pointers. For NSValue, you could do something like this:
NSValue *someIDMadeFromAClassInstance = [NSValue valueWithPointer:a_ptr_to_a_cpp_class_instance];
NSTableColumn *col = [[NSTableColumn alloc] initWithIdentifier:someIDMadeFromAClassInstance"];
// ...
NSValue *columnIdentifer = (NSValue *)[aTableColumn identifier];
MyCPPClass* pAValidClass = (MyCPPClass *)[columnIdentifer pointerValue];
pAValidClass->AClassMethod();

ARC/ObjC++: C++ object inside an ObjC container

Consider:
class SomeCppClass {
public:
SomeCppClass() {} ;
~SomeCppClass() {} ;
} ;
#interface Test1 : NSObject
- (id) init ;
#property (strong, nonatomic) NSMutableArray * container ;
#end
#implementation Test1
#synthesize container ;
- (id) init {
if (self = [super init]) {
container = [NSMutableArray arrayWithCapacity:10] ;
[container addObject:[NSValue valueWithPointer:new SomeCppClass()]] ;
}
return self ;
}
- (void) dealloc {
for (NSValue * v in container) {
SomeCppClass * c = (SomeCppClass *) [v pointerValue] ;
delete c ;
}
}
#end
Is this the correct approach to delete C++ land objects when you're done with them under ARC?
This will work, but you may consider a couple of other approaches to avoid the NSValue:
Create an ObjC wrapper that manages a single instance of SomeCppClass (and deletes just that one object in its dealloc). This can make them a bit easier to deal with in many cases (automatically converting std::string to NSString in the accessors, etc.) This is basically what NSValue is doing for you, but you get much more flexibility by creating your own custom class. This is usually my preferred approach.
Store the C++ objects in a C++ container such as vector and then you just have to delete the vector and it's easier to pull things out. You can used shared_ptr to put non-copyable objects into a vector. It is understandable if you don't want the overhead of STL and shared_ptr, but they are readily available in Cocoa.