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
/#import
ing or directly writing both Objective-C and C++ code in the same file. It's usually obvious with explicit code; the #include
s 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 #import
ing 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 #import
ing 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
Conditional Operator Used in Cout Statement
How to Export Templated Classes from a Dll Without Explicit Specification
Choosing Embedded Scripting Language for C++
What Does Lpcwstr Stand for and How Should It Be Handled With
Why Is Std::Fill(0) Slower Than Std::Fill(1)
Casting via Void* Instead of Using Reinterpret_Cast
How to Extract the Source Filename Without Path and Suffix at Compile Time
Should a Move Constructor Take a Const or Non-Const Rvalue Reference
How to Access Private Data Members Outside the Class Without Making "Friend"S
What's a Good Hash Function for English Words
Why Do Un-Named C++ Objects Destruct Before the Scope Block Ends
Creating a Counter That Stays Synchronized Across Mpi Processes
How to Get a Windows Symbol Server Set Up