Mixing Objective-C and C++

Mixing Objective-C and C++

You need to name your .m files .mm. And you will be able to compile C++ code with Objective-C.

So, following your example, your AView.m file should be named AView.mm. It's simple as that. It works very well. I use a lot of std containers (std::vector, std::queue, etc) and legacy C++ code in iPhone projects without any complications.

Mixing C++ and Objective C

You need to use Objective-C++ whenever you are either #include/#importing or directly writing both Objective-C and C++ code in the same file. It's usually obvious with explicit code; the #includes are often less so, and you need to take care to avoid "leaking" one of the languages into too much of the other. Your example of #importing a C++ header file is clear-cut: you can only do that with Objective-C++. Note that if your Cplusplus was a struct type, you could forward-declare it as such instead of #importing a C++ header.

If you do this in a header, it will "poison" the header to only work in that mode. You'll need to actively avoid this, or your whole project will soon end up with only .mm files. I have documented some techniques in this article and previously, in this earlier article. For newer versions of Objective-C, you can also add ivars to classes in category extensions. This means you can define C++-typed ivars in your .mm file, not the header, which allows .m files to #import it.

For your second question (Please only ask one question at a time): the id type is defined in the objc.h header file in terms of C and thus will work in both Objective-C and C++. Likewise, the Objective-C runtime API is exposed in terms of C functions, which will work from C++, too. If you actually want to send messages and access properties on Objective-C objects with the canonical syntax from C++ code, you'll need to switch that file to Objective-C++.

Can I mix Swift with C++? Like the Objective-C .mm files

No. When you switch from .m to .mm you are actually switching from Objective-C to a different language (which has many subtle differences) called Objective-C++. So you're not really using C++; you're using Objective-C++ which accepts most C++ as input (in the same way that C++ accepts most but not all C as input). When I say it's not quite C++, consider a C++ file that includes a variable named nil (which is legal C++) and then try to compile that as Objective-C++.

Swift doesn't have the same relationship. It is not a superset of C or C++, and you can't directly use either in a .swift file.

"Using Swift with Cocoa and Objective-C" also tells us:

You cannot import C++ code directly into Swift. Instead, create an Objective-C or C wrapper for C++ code.

Mixing C functions in an Objective-C class

Mixing C and Objective-C methods and function is possible, here is a simple example that uses the SQLite API within an iPhone App: (course site)

Download the Zip file (09_MySQLiteTableView.zip)

C functions need to be declared outside of the @implementation in an Objective-C (.m) file.

int MyCFunction(int num, void *data)
{
//code here...
}

@implementation

- (void)MyObjectiveCMethod:(int)number withData:(NSData *)data
{
//code here
}

@end

Because the C function is outside of the @implementation it cannot call methods like

[self doSomething]

and has no access to ivars.

This can be worked around as long as the call-back function takes a userInfo or context type parameter, normally of type void*. This can be used to send any Objective-C object to the C function.

As in the sample code, this can be manipulated with normal Objective-C operations.

In addition please read this answer: Mixing C functions in an Objective-C class

Mixing C with Objective C

graph is not a pointer in your method, so it is getting copied to a new memory location, apart from the original variable. It is like passing in an int or float. This is what is called passing by value.

The C method, however, is using pass by reference. It takes the pointer to graph rather than copying the value.

Since this is an ivar, you can access the pointer to _processingGraph directly:

- (void) createAUGraph {
NewAUGraph (&_processingGraph);
CAShow (_processingGraph);
}

Or, if you need to pass in different graphs at different times, you want the method to take a pointer to an AUGraph, use pass by reference:

- (void) createAUGraph:(AUGraph*) graph {
NewAUGraph (graph); // Since graph is now a pointer, there is no
// need to get a pointer to it.
CAShow (_processingGraph);
}

And call the method like so:

[self createAUGraph:&_processingGraph];

While that fixes the arguments, be sure to read danh's answer below for a better way to create structs.

I need help mixing C++ code and Objective-C code

I have tried to to bundle up the C++ bits into a Obj-C class extension as noted here, but without much success.

If you're targeting 64-bit, the class extension method should be fairly simple.

The following is equivalent to the code you've post, but moves all of the C++ declarations to a separate header:

SyncController.h:

#import <Cocoa/Cocoa.h>

@interface SyncController : NSObject
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
@end

SyncController_CPP.h

#import "SyncController.h"
#include "DeckLinkAPI.h"

class PlaybackDelegate;

@interface SyncController() {
PlaybackDelegate* playerDelegate;
IDeckLink* deckLink;
IDeckLinkOutput* deckLinkOutput;
}
@end

class PlaybackDelegate ...
{
...
}

SyncController.mm

#import "SyncController_CPP.h"

@implementation SyncController
...
@end

PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
mController = owner;
mDeckLinkOutput = deckLinkOutput;
}

// etc..

Any other ObjC classes that need access to SyncController will import "SyncController.h". Any other ObjC++ classes can import either "SyncController.h" or "SyncController_CPP.h"

self' is not a valid target. Mixing Objective-C and C++ (Objective-C++)

I believe the exception is coming from a statement within the implementation of -[MPRemoteCommand addTarget:action:] that looks something like:

NSParameterAssert(target);

That is, it's validating that the target parameter it has received is non-nil. That's why the odd phrasing "… parameter not satisfying: target". "target" is the actual condition being tested and which the parameter does not satisfy. If the statement had been written NSParameterAssert(target != nil); then the exception reason would have read "… parameter not satisfying: target != nil", which would have been clearer.

Anyway, you write a (presumably non-nil) value to selfRef in IosImpl::init(), but what calls that? The constructor does not as currently written. Either call init() from the constructor or just put that code directly into the constructor.

Also, your destructor isn't correct. As currently written, it's calling -dealloc on the Ios_objc class object, which is unlikely to do anything (and, if it does, it's nothing good). You probably meant [selfRef release] (note: release, not dealloc). In general, you should never call -dealloc except to call through to super in an implementation of your own -dealloc method.

Mixing C++ and Objective-C

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



Related Topics



Leave a reply



Submit