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();
Related
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)")
...
Assigning names to my objects (like the ones returned from the global Instantiate method) is breaking my tests. Anyone have any ideas for how to get around such things in test?
using System;
using NUnit.Framework;
using UnityEngine;
[TestFixture()]
public class BoardSpec{
[Test()]
public void NamePropertyWorks(){
var obj = new UnityEngine.Object();
obj.name = "object name";
}
}
The error I'm receiving: System.MissingMethodException : Cannot find the requested method.
The first line of the stack trace gives: at (wrapper managed-to-native) UnityEngine.Object:set_name (string)
Unity 5.2.0f3, running tests in MonoDevelop-Unity 4.0.1 on osx
_____update 9/20______
It sounds like creating new Objects is not recommended, but this code fails with the same error:
[Test()]
public void ScriptableObjectNamePropertyWorks(){
var obj = new ScriptableObject();
obj.name = "object name";
}
Short answer: Never create nor inherit directly form UnityEngine.Object, use ScriptableObject instead
Doing something like (new UnityEngine.Object()).name = "text" will always throw a null reference exception, as I'll explain below. From there to the System.MissingMethodException you are getting, it depends on the inner workings of NUnit.
Unity uses UnityEngine.Object in a very special way, keeping track of objects, and considering some "not alive" despite existing. The Equals comparison for UnityEngine.Object is overriden to reflect this, and an existing Object might equal null:
// Both Mesh and MyObject inherit directly from UnityEngine.Object
Object plainObject = new UnityEngine.Object();
Mesh meshObject = new UnityEngine.Mesh();
MyNumber myNumber = new MyNumber(123456f);
// using the overriden Unity.Object.Equals()
print(plainObject != null); // false
print(meshObject != null); // true
print(myNumber != null); // false
// With traditional null checking, everything exists of course, as we just created them
print(plainObject as System.Object != null); // true
print(meshObject as System.Object != null); // true
print(myNumber as System.Object != null); // true
print(myNumber.number); // prints 123456, the object is there and perfectly operational
print(myNumber.name); // the program ends with a null reference exception thrown by the name set accessor, because myNumber is not "alive"
Every native Unity class that inherits from UnityEngine.Object makes any needed internal call to register the object as "alive", but this is not done in the base class itself. Basically, any attempt to create a vanilla Object, or something directly inherited from it, will be considered stillborn by the engine, and you won't get it to work as usual. If you need to create or inherit from Objects, use ScriptableObject instead, that has an explicitly special behaviour in the inner workings.
Consider the following example:
function Process()
local Container=NewContainer()
Container:On(EventType.Add,function()
Container:DoSomething()
end)
-- Does not Garbage Collect
end
In luabridge, I store the function() as LuaRef which extends the lifetime for the Container and it will not be GCed because it's a RefCountedObjectPtr
Here is a workaround that I use to use a weak table which works, but it looks ugly:
function Process()
local Container=NewContainer()
local ParamsTable={ Container=Container }
setmetatable(ParamsTable, { __mode = 'k' })
Container:On(EventType.Add,function()
ParamsTable.Container:DoSomething()
end)
-- Garbage Collects fine
end
Is there any way to have a LuaRef that functions similar to this? Or maybe there is another workaround?
Here is the way I approached this problem:
Create a wrapper class around C++ luabridge class (If you have class Display.A() in C++, create class A() in Lua)
Store a weak table inside that wrapper class (self.WeakTable={} and setmetatable(self.WeakTable, { __mode = 'k' }))
In the weak table, reference self: (self.WeakTable.self=self)
Pass self.WeakTable to C++ and store in as LuaRef - this will gc
Create a wrapper function like so:
Container:On(EventType.Add,function(WeakTableParams)
WeakTableParams.self.Callback();
end)
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;
}
I'm using Visual Studio 2008 Professional in C++ with Windows Form, I have a class that I have to pass to the other Form, so here is what I'm doing
//FirstFile.cpp
Usuario user;
user.usuario = "test";
user.senha = "stackoverflow";
ChooseService cs(user);
cs.ShowDialog();
//SecondFile.cpp
public ref class ChooseService : public System::Windows::Forms::Form
{
public:
Usuario* usuario;
ChooseService(Usuario user)
{
usuario = user;
//I need to cast the Usuario into Usuario*, so I can use it in the class
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
/...
as I said in my comment, I need to cast "Usuario" into "Usuario*" so I can access in the class using "this", by the way I can't make this
Usuario usuario;
instead of pointer, because windows forms doesn't allow you, you have to use pointer. so how do I do this? is there any trick?
I hope I was clear enough, Thanks!
Getting the pointer from an object is easy:
Usuario user;
Usuario* pUser = &user;
But it might render the pointer invalid, because user is in automatic storage and might be destroyed before you're done using pUser.
I suggest you allocate user dynamically and modify the constructor of ChooseService to take a pointer:
Usuario* user = new Usuario;
user->usuario = "test";
user->senha = "stackoverflow";
ChooseService cs(user);
//...
ChooseService(Usuario* user) {...}
In your particular case, your variant would work because both objects have the same lifetime, but it's dangerous in the long run.
You wouldnt cast, you just take the address