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);
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 recently began learning OOP concepts in C++ and tried making a simple Tic-Tac-Toe game with classes. My Game class's game loop gets input from the user, which is where I am having this problem. I created an InputHandler class that the Game class has an instance of, and in the game loop I call inputHandler.input(). If the player types "restart", I want the game to restart by calling game.restart(), however my InputHandler object does not have an instance of the game. So my current solution is to pass the game by reference to the InputHandler object so I can call game.restart() from there, however this seems like bad practice from everything I have learned about OOP. Also, for every function that does something similar to this, I would need to pass the game object by reference there also. I feel like I am missing something fundamental about OOP design. Is it bad to pass the game object by reference, or is there a better way solve this problem?
//game.cpp
void Game::run() {
while(!gameOver) {
inputHandler.input(this);
}
}
//inputHandler.cpp
void InputHandler::input(Game& game) {
std::string input;
std::cin >> input;
if (input == "restart") {
game.restart();
}
}
One way to deal with special action is to pass a handler function (aka callback). The C++ way would be a std::function<void()> which can be triggered upon specific events being detected:
class SomeClass {
...
std::function<void()> d_restartHandler;
public:
void setRestartHandler(std::function<void()> handler) { d_restartHandler = handler; }
void doSomething() {
...
if (timeToRestart && this->d_restartHandler) {
this->d_restartHandler();
}
...
}
};
The function template std::function<Signature> can actually be parameterized by suitable parameters, too, by instantiating it with a suitable signature. If you feel that this approach isn't object oriented: it actually is! Internally, std::function<Signature> holds a hierarchy with a base class can a concrete class holding the actual function object to dispatch to. You can even implement something similar yourself but I'd think that would be a pointless waste of time.
Assuming you have your SomeClass instance sc and your Game instance g, you could register for a restart using something like
sc.setRestartHandler([&](){ g.restart(); });
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.
I have a C++ project on iOS. It mostly uses C++, except for some tasks that require Objective-C. For instance, showing a UIAlert.
So I call the UIAlert from C++. How do I get the result and know what was the button tapped by the user?
This is the implementation of the C++ class calling to Objective-C
void iOSBridge::iOSHelper::ShowAlert()
{
[IsolatedAlert showAlert];
}
And here I have the Objective-C implementation:
+ (void)show{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message: #"hello"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
}
+ (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
}
Is there any way to call C++ again from clickedButtonAtIndex delegate?
Thanks.
There's nothing preventing you from calling a C++ class from an Objective C one. You'll need to provide your Objective C class with some sort of a handle to the C++ class, which it will need to store as an instance variable. Then you can do whatever you want with it.
That's going to be awkward to accomplish while you're only using class methods like you are. It'll be better to use instance methods, and then create an instance from the C++ side, provide the instance with a handle, then send messages to the instance instead of the class.
Make the extension of this class as .mm
Then have an static var YourClaas *delegate; in it
+ (void)showAlertWithDelegate:(YourClass*)del{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message: #"hello"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
delegate = del;
[alert show];
[alert release];
}
+ (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
del->buttonClickAtIndex(buttonIndex);
}
and define void buttonClickAtIndex(int index) method in your cpp file
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.