I have an objective-c member in c++ class:
#interface ObjectiveCClass : UIViewController {
int someVarialbe;
}
- (void)someFunction;
- (void)dealloc;
#end
#implementation ObjectiveCClass
- (void)someFunction{
//Log of someFunction
}
- (void)dealloc {
//Log line of objective-c dealloc
[super dealloc];
}
#end
class CPlusPlusClass{
ObjectiveCClass obj; // have a objective c member
CPlusPlusClass(){
obj = [[ObjectiveCClass alloc] init];
~CPlusPlusClass(){
//Log line of C++ class destructor
obj.someFunction;
[obj release];
}
};
I'm calling explicitly the release of objective-c member object from the destructor of the C++ class. I do see the log line of C++ class destructor and the log of some function, but!!!, DONT see the log line of the dealloc.
Should I do something different?
Related
I have a unique use case where I am using CoreBluetooth in my C++ application. There are a lot of old tutorials on CoreBluetooth implementation for objective c and my code looks familiar to this. My problem is that after initializing CBCentralManager, centralManagerDidUpdateState is not being called.
wrapper.h file for c++
// this file defines c++ functions to be used in the .mm file
void *get_object();
.h file for objective c
#import "wrapper.h"
#interface MyObject : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate>
#property(strong, nonatomic) CBCentralManager *centralManager;
- (id)init;
- (void)initialize_manager;
#end
.mm file
// declared in wrapper.h, this is a c++ method to return a void pointer to MyObject
void *get_object() {
void *obj_ptr = [[MyObject alloc] init];
return obj_ptr;
}
// this is the objective c code
#implementation MyObject
- (id)init {
self = [super init];
if (self) {
// this is where the central manager should be created
[self initialize_manager];
}
return self;
}
- (void)initialize_manager {
_centralManager = [[CBCentralManager alloc] initWithDelegate:self
queue:nil
options:nil];
}
// this should get called immediately after initialize_manager
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
std::cout << "this never gets called" << std::endl;
NSLog(#"this never gets called");
.cpp file to test it
void *p = get_object();
Summary of code:
In my .cpp file I am calling get_object() which initializes a new MyObject and returns a void pointer to it. When initializing a new MyObject, it calls initialize_manager() which should (but currently doesnt call) call centralManagerDidUpdate.
Previous issue I found of centralManagerDidUpdateState not being called:
Their problem was they didn't assign the central manager to an instance variable. However, I did so doesn't seem like that applies to me.
Not sure if this is a problem with objective-c++ not handling delegates properly, or if storing MyObject as a void* pointer messes with some internal magic.
Also maybe it is because my program exits too soon? Every implementation of CoreBluetooth I've seen is used in a ViewController, can I replicate the non terminating aspect of a view controller in C++? Maybe it's something to do with async issues? Would appreciate any pointers!
update 1: I think CoreBluetooth may be sharing the same thread as the main c++ application
Posting this short answer for now, will edit as a get cleaner iterations. The problem is that the objective c library (CoreBluetooth) needed to be run on a different thread than my main application.
stay tuned for code implementation
I try to make a Code Connection with my game object (which is located in Enemy.ccb) in SpriteBuilder.
It works perfect when I just load my object and add it to the stage.
CCNode *enemy = [CCBReader load:#"Enemy"];
[self addChild:enemy];
Unfortunately it will not work when I set the custom class of the object to 'Enemy'. The asset is loading and its custom class is initializing, but it is not shown. What I am doing wrong?
EDIT:
Here's my simple implementation of the Enemy class. It is subclassed from CCSprite:
#implementation Enemy
- (id)init {
self = [super init];
if (self) {
CCLOG(#"Enemy created");
}
return self;
}
#end
Hello I know that this problem was discussed several times, but I have feeling that no other explenation works for me. Maybe it isn't possible but... at the moment I have mm file it looks like (init methods/ header file) obj-c except few C++ methods (library live555 which I use is written in C++), and I can call C++ methods form obj-c just fine. But when I want call obj-c in c++... then I got error. I know self isn't know. But how I can move aroud it? I try with 2-3 tuts but all of them assume that obj-c method isn't called inside that obj-c++ class.
My Obj-C++ class (.mm file)
#interface testSender : NSObject{
#private
NSMutableArray *_buffors;
}
+(id)voiceSender;
//Function to invoke
-(bool)continueSendBuffer;
#end
#implementation testSender
#synthesize address=_address,port=_port;
UsageEnvironment* env;
+(id)voiceSender{
return [[self alloc]init];
}
- (id)init
{
self = [super init];
if (self) {
[self initRTPProt];
_buffors = [NSMutableArray array];
}
return self;
}
-(void)initRTPProt{
//init protocol
}
void afterPlaying(void* clientData); // forward
void afterPlaying(void* /*clientData*/) {
// We and stream and now I want check if it's some other streams to send so normaly I should call
[self continueSendBuffer];
}
-(bool)continueSendBuffer{
if ([_buffors count] == 0) return false;
NSData *nextBuffer = [_buffors objectAtIndex:0];
[_buffors removeObjectAtIndex:0];
[self sendNextBuffer:nextBuffer];
return true;
}
-(void)sendNextBuffer:(NSData*)buffer{
// Send next buffer
/setting sessionState..
// Start the streaming:
*env << "Beginning streaming...\n";
// Method afterPlaying will be called after ther will be nothing to send
sessionState.sink->startPlaying(*sessionState.source, afterPlaying, NULL);
env->taskScheduler().doEventLoop();
}
#end
At c++ method void afterPlaying(void*) when I want use [self continueSendBuffer] then I got error Use of undeclared identifier 'self'.
Solved
Chuck did great job and explain me how Objective-C++ works. Read it!
Basically you just can't call obj-c method in "c++ method" (I know there are free floating methods) with out passing to them self pointer.
I have to modify a bit startPlaying call and now in third argument I pass self pointer
Also method afterPlaying had to been change so now she can use clientData pointer. Throught this I can call continueSendBuffer.
startPlaying
sessionState.sink->startPlaying(*sessionState.source, afterPlaying, (__bridge void*)self);
afterPlaying
void afterPlaying(void* clientData) {
[(__bridge NXVoiceSender*)clientData continueSendBuffer];
}
Objective-C++ does not unify C++ classes and Objective-C classes. It allows you to mix Objective-C code and C++ code, but the two object models are still completely separate — it basically just uses C++ where C would be used in normal Objective-C. What you're calling "C++ methods" there are actually just free-floating functions, because an Objective-C class definition isn't a special context in C++. They are not methods of the class.
You'll somehow need to keep a pointer to the object in question and get that into the afterPlaying() function (and also keep the object alive long enough to be referenced when afterPlaying() is called). I'm not familiar with the library, but that clientData parameter looks promising.
The type of the second argument of startPlaying is std::function? If so, you can pass a Block instead of C++11 lambda for that as the following with "C++ Language Dialect" to "C++11".
__weak testSender *self_ = self;
sessionState.sink->startPlaying(*sessionState.source, ^(void *){
// We and stream and now I want check if it's some other streams to send so normaly I should call
[self_ continueSendBuffer];
}, NULL);
I am porting a game using native C++ for Android. I need to know which method I should use to achieve the same functionality as NSURLConnection and NSURLRequest in only C++. Also how to get all the following delegate functions implemented for C++.
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
Please advise.
There is no way to implement Objective-C delegate methods in C++ directly. The best you can really hope to do is to use Objective-C++ to make a C++ object with an instance variable that is an Objective-C object whose sole purpose is to be the NSURLConnection delegate and forward those method calls to the owning C++ object. The C++ object should own/retain the Objective-C object, and be responsible for plugging it in as the delegate of the NSURLConnection object.
An extremely naive implementation of the above described pattern might look like this:
URLConnection.h
#ifndef __Cplusplus__URLConnection__
#define __Cplusplus__URLConnection__
#include <string>
class URLConnection
{
public:
URLConnection(std::string url);
~URLConnection();
void DidReceiveResponse(const void* response);
void DidReceiveData(const void* data);
void DidFailWithError(std::string error);
void DidFinishLoading();
void* mNSURLConnection;
void* mDelegate;
};
#endif /* defined(__Cplusplus__URLConnection__) */
URLConnection.mm
#include "URLConnection.h"
#interface PrivateNSURLConnectionDelegate : NSObject <NSURLConnectionDelegate>
{
URLConnection* mParent;
}
- (id)initWithParent: (URLConnection*) parent;
#end
#implementation PrivateNSURLConnectionDelegate
- (id)initWithParent: (URLConnection*) parent
{
if (self = [super init])
{
mParent = parent;
}
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
mParent->DidReceiveResponse(response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
mParent->DidReceiveResponse(data.bytes);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
mParent->DidFailWithError(std::string([[error description]UTF8String]));
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
mParent->DidFinishLoading();
}
#end
URLConnection::URLConnection(std::string url)
{
this->mDelegate = [[PrivateNSURLConnectionDelegate alloc] initWithParent: this];
NSURLRequest* req = [NSURLRequest requestWithURL: [NSURL URLWithString: [NSString stringWithUTF8String: url.c_str()]]];
this->mNSURLConnection = [[NSURLConnection alloc] initWithRequest: req delegate: (id)this->mDelegate];
}
URLConnection::~URLConnection()
{
[(NSObject*)this->mNSURLConnection release];
[(NSObject*)this->mDelegate release];
}
void URLConnection::DidReceiveResponse(const void* response)
{
// Do something...
}
void URLConnection::DidReceiveData(const void* data)
{
// Do something...
}
void URLConnection::DidFailWithError(std::string error)
{
// Do something...
}
void URLConnection::DidFinishLoading()
{
// Do something...
}
At the end of the day, NSURLConnection is an Objective-C object. There's no way to interact with it without using Objective-C.
LibCURL is maybe the best-known library for cross-platform C/C++ implementation of handling network/internet connections. If you combine it with an asynch technology like threads, you can begin to simulate NSURLConnection.
See here [https://curl.haxx.se/libcurl/c/multithread.html] for an example. You'll have to create a class that manages the CURL reference and an appropriate std::function delegate, that you will call when the connection finishes/errors/aborts etc. When using it, you can pass C++14 lambda functions to act as stand-ins for Objective C delegates.
How do you handle the setAction message in Objective-C++? (Not Objective-C.)
For example, suppose I have:
my_class.mm
NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
[segmented setSegmentCount:5];
// etc.
[segmented setAction:???];
Application: I am programming in Qt (C++) and need a wrapper around some Cocoa widgets I want to use directly. I am inheriting from QMacCocoaViewContainer but can't figure out how to handle the "clicks" of the NSSegmentedControl I am wrapping. Eventually this will emit a standard Qt signal.
action is just a selector - it is used in tandem with target. so write an objc method for target+action which calls through or does what you really want. actions' arguments are the sender, but you can omit that if you don't need it. the sender will be whatever is sending the message (e.g. the control). it's no different in ObjC++ - this has to be wrapped in an objc method because the target must be an objc object.
so it would look like this:
obj.action = #selector(pressDoStuff:);
and the method is:
- (void)pressDoStuff:(id)sender
#Justin has the right answer; I'll accept it, but also include the final solution in case it helps others. The trick is you need a proxy class, as #smparkes noted.
Ignoring the .h files for brevity:
mac_control.mm
MacControl::MacControl(QWidget *parent) : QMacCocoaViewContainer(NULL, parent) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
// Set up NSSegmentedControl...
// The proxy class marshalls between Objective-C and C++.
proxy_ = [[MacControlProxy alloc] init];
[proxy_ setTarget:this];
[segmented setTarget:proxy_];
[segmented setAction:#selector(handleToggle:)];
setCocoaView(segmented);
[segmented release];
[pool release];
}
MacControl::~MacControl() {
delete proxy_;
}
void MacControl::TriggerAction(int index) {
// Trigger the action in Qt/C++.
}
mac_control_proxy.mm
#implementation MacControlProxy
- (id)init {
[super init];
target_ = NULL;
return self;
}
-(void) handleToggle: (id)sender {
if (target_) {
target_->TriggerAction([sender selectedSegment]);
}
}
-(void) setTarget: (MacToolbarButtonControlImpl*)target {
target_ = target;
}
#end
I'm following up on Dave Mateer's answer (which was super helpful!).
I was having issues setting the C++ target (from within a objective-C++ class) and used [NSValue valueWithPointer:theTargetCxxClass] to pass the target to the Proxy.mm class.
So, inside of my Objective-C++ class, rather than doing this:
[proxy_ setTarget:this];
I did this:
[proxy_ setTarget:[NSValue valueWithPointer:this]];
or
[proxy_ setTarget:[NSValue valueWithPointer:ptrToMyCxxObject]];
And doing this got rid of an error about passing a C++ class (which does not extend type "id") to the Objective-C++ proxy class.
Inside of the proxy class, you then need to use NSValue's pointerValue method and then cast back to the C++ class in order to send a message to it.
-(void) myButtonAction: (id)sender {
((MyCxxClass*)[target pointerValue])->someMethodInMyCxxClass();
}
I first was alerted to the "valueWithPointer" trick in this post.