How could NSArray take ownership of a c++ object - c++

As I know, c++ object in iOS is allocated in the stack memory. Now I have to add the c++ object into a NSArray, however NSArray cannot store c++ objects directly.
The question is how could I store a c++ object in a NSArray and let the NSArray take ownership of the c++ object so that I could use the c++ object whenever I want.
Thanks for any help!
=========EDIT========
Here are some code snippet:
std::list<ImageTextContent> msgs = body->getMsgs();
std::list<ImageTextContent>::iterator itmsgs0;
for(itmsgs0 = msgs.begin();itmsgs0 != msgs.end();itmsgs0++)
{
ImageTextContent *tmpmsgs = &(*itmsgs0);
ImageTextContentWrapper *itc = [[ImageTextContentWrapper alloc] initWithImageTextContent:tmpmsgs];
[self.dataSource addObject:itc];
}
[self.tableview reloadData];
the cellForRow method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
........
ImageTextContentWrapper *itc = (ImageTextContentWrapper *)[_dataSource objectAtIndex:indextPath.row];
NSString *title = [NSString stringWithCString:(itc.imageTextContent->getTitle()).c_str() encoding:NSUTF8StringEncoding];
cell.titleLabel.text = title;
........
}
ImageTextContentWrapper class:
#interface ImageTextContentWrapper : NSObject
#property (nonatomic, assign) ImageTextContent *imageTextContent;
- (id)initWithImageTextContent:(ImageTextContent *)imageTextContent;
#end
#implementation ImageTextContentWrapper
- (id)initWithImageTextContent:(ImageTextContent *)imageTextContent
{
if (self = [super init])
{
self.imageTextContent = imageTextContent;
}
return self;
}
#end

Create an Objective-C class owning your C++ object, and store objects of this class in NSArray.

A small code example how to wrap a C++ object in a Objective-C class:
For a C++ class CPP which could look like
class CPP {
public:
std::string aName;
CPP(std::string aName) : aName(aName) { }
};
you can create a Objective-C wrapper class ObjectiveC:
// ObjectiveC.h
#interface ObjectiveC : NSObject
{
CPP *cpp;
}
- (id)initWithString:(NSString*)string;
- (void)print;
#end
//ObjectiveC.mm <- this .mm tells Xcode to use the right compiler
#import "ObjectiveC.h"
#implementation ObjectiveC
- (id)initWithString:(NSString*)string
{
self = [super init];
if (self)
{
cpp = new CPP([string UTF8String]);
}
return self;
}
- (void)print
{
NSLog(#"%s", cpp->aName.c_str());
}
#end
Now you can create a NSArray containing indirectly containing the C++ objects:
// main.mm for example (.m -> .mm !)
ObjectiveC *oc1 = [[ObjectiveC alloc] initWithString:#"oc1"];
ObjectiveC *oc2 = [[ObjectiveC alloc] initWithString:#"oc2"];
ObjectiveC *oc3 = [[ObjectiveC alloc] initWithString:#"oc3"];
NSArray *array = [[NSArray alloc] initWithObjects:oc1, oc2, oc3, nil];
for (ObjectiveC *oc in array) {
[oc print];
}
A small remark: You have to change all implementation files containing and interacting with this wrapper files from .m to .mm. The second option is to change the compiler in the Xcode settings.

You're off the mark a little. There are two ways to create C++ objects. On the stack (by declaring it as a local, non-pointer variable) or on the heap (e.g. using operator new or by declaring it as a non-pointer instance variable in an ObjC object).
If you actually have one on the stack, there is no way to (safely) reference it from an ObjC class. In ObjC, all objects are on the heap, so everyone who retains it is guaranteed that it will stay around even if the function in which it is declared returns. And the last one who releases it causes its memory to actually be freed.
You can't give that guarantee with stack objects, as they must go away the moment the function in which they are a local variable returns.
But if you could create your C++ object with operator new and your code would still work, instead of a stack object, then you can just create an ObjC class in an ObjC++ file (.mm suffix instead of straight .m), and put that in an array. If you want to learn more about ObjC++, I recommend you listen to my guest spot on the NSBrief podcast, where I talk about ObjC++ in detail.
Alternately, what reason prevents you from just putting your C++ object in a std::vector instead of an NSArray? What are you hoping to use this NSArray full of C++ objects for?
PS - For completeness' sake, let me also mention that there is +NSNumber numberWithNonretainedPointer: (or maybe it was "unretained") which you could use as a pre-made object for keeping a pointer in an array, but this is not recommended, as it does not call delete on the pointer when it is released, so you have to be very careful or you'll leak C++ objects. Better to make your own class.

Related

C++ object as an Objective-C++ property

I want to declare a C++ property inside my Objective-C class.
What kind of attributes should I set it to? It seems that strong or retain will lead to an error saying that it is not an object.
How could I manage its memory properly?
You are right, the property cannot be weak, strong, or retained; for that it would have to be a pointer to an Objective-C object. If you don't use any attributes on a C++ property, it will default to unsafe_unretained,assign,atomic.
A few other things to consider, assuming the Objective-C(++) object controls the lifetime of the C++ property:
Because you can't do much with a C++ object in Objective-C, the
property is mostly useful in Objective-C++ code, where you can mix
Objective-C and C++.
Because you have to manage the property's memory on your own, you
need a custom setter.
Because the property defaults to atomic, you need to use
synchronization in the setter and need a custom getter, too. You
could declare it nonatomic, in which case you would not need to
synchronize and would not need a custom getter.
You can implement dealloc to ensure the C++ object is freed when
the Objective-C++ object goes away.
Here's some useful documentation from Apple: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html.
And here is a quick example. Let's say the C++ class you are using for the property is called MyCPP. In a header you could have:
#interface ClassOCPP : NSObject
// This property can only be used in Objective-C++ code
#ifdef __cplusplus
#property /*(unsafe_unretained,assign,atomic)*/ MyCPP * myCPP;
#endif
// Other stuff may be usable in regular Objective-C code.
#end
Implementation could be as follows (in a .mm file; remember, it's Objective-C++):
#implementation ClassOCPP
{
MyCPP * _myCPP;
}
-(id)init {
self = [super init];
_myCPP = NULL;
return self;
}
-(void)setMyCPP:(MyCPP*)newVal {
#synchronized(self) {
delete _myCPP; // it's OK to delete a NULL pointer
_myCPP = newVal;
}
}
-(MyCPP*)myCPP {
return _myCPP;
}
-(void)dealloc {
puts("De-allocating ClassOCPP.");
delete _myCPP;
}
#end
IIRC, you need to manage it like any other C++ object, so just use assign as the attribute, and you should be good.

How to pass and convert Array objects from swift/objective-c to C++?

I have array of objects named photoArray and it has property date and index. I can access that like photoArray[arrayIndex].index / photoArray[index].date.
I am C++ developer so i code all my logics in c++. I want to pass this objects from Swift to c++ . I have created C++ class and its header . Then I have then created C++ wrapper class in objective- c and its header with definition. Also created the bridging header.
My question - What shall be the code snippet in my CPP-wrapper.mm just like I have done with string. Also What should be the data type in my CPP.cpp class?
My goal is to print this photoArray from c++. Let me know if it is possible to do so or any clarification needed.
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let world = " passed as string"
CPP_Wrapper().hello_cpp_wrapped(world)
getPhotos()
func getPhotos() {
let photoLibraryAccess = PhotoLibraryAccess();
photoLibraryAccess.authenticate {
let photoArray = photoLibraryAccess.getPhotos()
CPP_Wrapper().eventclassification_cpp_wrapped(photoArray) // pass to c++} }}
CPP.cpp
void CPP::hello_cpp(const std::string& name) {
cout << "Hello " << name << " in C++" << endl; }
void CPP::event_classification(const int * objectArray){
// instead of int it should be name of class ?
cout<<objectArray[1]; }
CPP-Wrapper.mm
#implementation CPP_Wrapper
- (void)hello_cpp_wrapped:(NSString *)name {
CPP cpp;
cpp.hello_cpp([name cStringUsingEncoding:NSUTF8StringEncoding]);}
- (void)event_classification_cpp_wrapped:(NSArray *)eventArray {
CPP cpp;
cpp.hello_cpp() // what should be the conversion code? }
#end
PhotoLibraryAccess.h
#interface PhotoIndexDate : NSObject
#property (nonatomic, assign) NSUInteger index;
#property (nonatomic, copy, nonnull) NSString * date;
#end
#interface PhotoLibraryAccess : NSObject
- (void)authenticate:(void ( ^ _Nonnull )())completion;
- (nonnull NSArray <PhotoIndexDate *> *)getPhotos;
#end
The problem here is that your photo type, PhotoIndexDate, is an Objective-C type that cannot be used in C or C++. Here are some options you've got:
Use a C struct to hold info about a photo. The struct can be used in
Swift, Objective-C, and C++. Using an array of these structures in Swift may be a little tricky, though.
Use NSArray <PhotoIndexDate *> to store the photos like you do
now, but build a C array of C/C++ objects from it in
event_classification_cpp_wrapped and send it to a C++
classification method.
Similar to the previous option, but instead of building an array
of C/C++ objects and sending it to C++, iterate through the array,
build a C/C++ photo object from it and send it to C++ one at a
time.
Which option you choose depends on a few things, such as:
Do you want to make changes to the photo array in C++ such that the
changes are visible back in Objective-C or Swift code?
Do you mind creating a copy of the whole Swift/Objective-C array in
C++? Is it OK from memory usage perspective?

Writing a C++ Wrapper around Objective-C

I want to call and work with Objective-C classes from within a C++ project on OS X. It is time to start moving towards all Objective-C, but we need to do this over some time.
How does one go about accomplishing this? Can anyone shed some light and provide an example?
Objective-C++ is a superset of C++, just as Objective-C is a superset of C. It is supported by both the gcc and clang compilers on OS X and allows you to instantiate and call Objective-C objects & methods from within C++. As long as you hide the Objective-C header imports and types within the implementation of a C++ module, it won't infect any of your "pure" C++ code.
.mm is the default extension for Objective-C++. Xcode will automatically do the right thing.
So, for example, the following C++ class returns the seconds since Jan 1., 1970:
//MyClass.h
class MyClass
{
public:
double secondsSince1970();
};
//MyClass.mm
#include "MyClass.h"
#import <Foundation/Foundation.h>
double MyClass::secondsSince1970()
{
return [[NSDate date] timeIntervalSince1970];
}
//Client.cpp
...
MyClass c;
double seconds = c.secondsSince1970();
You will quickly find that Objective-C++ is even slower to compile than C++, but as you can see above, it's relatively easy to isolate its usage to a small number of bridge classes.
I think it was Phil Jordan that really put forward the best C++ wrapped Obj-C formula. However, I think the latter, C++ wrapped by Obj-C is more useful. I'll explain why below.
Wrapping an Objective-C object with C++
Person.h - The Obj-C header
#interface Person : NSObject
#property (copy, nonatomic) NSString *name;
#end
PersonImpl.h - The C++ header
namespace people {
struct PersonImpl;
class Person
{
public:
Person();
virtual ~Person();
std::string name();
void setName(std::string name);
private:
PersonImpl *impl;
};
}
Person.mm - The Obj-C++ implementation
#import "Person.h"
#import "PersonImpl.h"
namespace people {
struct PersonImpl
{
Person *wrapped;
};
Person::Person() :
impl(new PersonImpl())
{
impl->wrapped = [[Person alloc] init];
}
Person::~Person()
{
if (impl) {
[impl->wrapped release]; // You should turn off ARC for this file.
// -fno-objc-arc in Build Phases->Compile->File options
}
delete impl;
}
std::string Person::name()
{
return std::string([impl->wrapped UTF8String]);
}
void Person::setName(std::string name)
{
[impl->wrapped setName:[NSString stringWithUTF8String:name.c_str()]];
}
}
#implementation Person
#end
Wrapping a C++ object with Objective-C
I often find the real problem isn't getting C++ to talk to Obj-C code, it's switching back and forth between the two where things get ugly. Imagine an object that needs to have C++-only items, but the basic object details are filled out in Obj-C land. In this case, I write the object in C++ and then make it so I can talk to it in Obj-C.
Person.h - The C++ header
namespace people
{
struct PersonImpl;
class Person
{
public:
Person();
Person(Person &otherPerson);
~Person();
std:string name;
private:
PersonImpl *impl;
}
}
Person.cpp - The C++ implementation
namespace people
{
struct PersonImpl
{
// I'll assume something interesting will happen here.
};
Person::Person() :
impl(new PersonImpl())
{
}
Person::Person(Person &otherPerson) :
impl(new PersonImpl()),
name(otherPerson.name)
{
}
~Person()
{
delete impl;
}
}
Person.h - The Obj-C header
#interface Person : NSObject
#property (unsafe_unretained, nonatomic, readonly) void *impl;
#property (copy, nonatomic) NSString *name;
#end
Person.mm - The Obj-C++ implementation
#interface Person ()
#property (unsafe_unretained, nonatomic) std::shared_ptr<people::Person> impl;
#end
#implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
self.impl = std::shared_ptr<people::Person>(new people::Person());
}
return self;
}
- (instancetype)initWithPerson:(void *)person
{
self = [super init];
if (self) {
people::Person *otherPerson = static_cast<people::Person *>(person);
self.impl = std::shared_ptr<people::Person>(new people::Person(*otherPerson));
}
return self;
}
- (void)dealloc
{
// If you prefer manual memory management
// delete impl;
}
- (void *)impl
{
return static_cast<void *>(self.impl.get());
}
- (NSString *)name
{
return [NSString stringWithUTF8String:self.impl->name.c_str()];
}
- (void)setName:(NSString *)name
{
self.impl->name = std::string([name UTF8String]);
}
#end
Regarding the void *
The second you stepped into the land of C++ you were going to feel some pain if you want to avoid your whole project being littered with .mm files. So, let's just say, if you don't think it is ever necessary to get your C++ object back out, or reconstitute the Obj-C object with the C++ object you can remove that code. It is important to note that the second you remove the Person instance from the Obj-C code through the void * method you had better make your own copy with the copy constructor or the pointer will become invalid.
First rename your files from *.m to *.mm so you get Objective-C++
I have not tired this, so it is speculation (I will tonight):
As all Objective-C++ objects (that are reference counted) are controlled via pointers so you can write a special destructor for shared pointer.
template<typename T>
struct ObjCDestruct
{
void operator()(T* obj)
{
[obj release];
}
};
Now you can stick your Objective-C obects in a boost::shared_ptr
// FuncFile.M
//
int func()
{
boost::shared_ptr<MyX, ObjCDestruct<MyX> > data([[MyX alloc] init]);
[data.get() doAction1:#"HI"];
}
Check out this question Calling Objective-C method from C++ method?
You will need to have some objective-c classes to wrap the code and expose with a C function.

iPhoneOS: using detachNewThreadSelector method inside a C++ class method

I have a C++ class method where i need to call the "detachNewThreadSelector" method with all the parameters.
Here lies the problem, as my class is not objective C i don't have a self pointer. Also i don't see how i will be able to call a class method from the method that i will set as selector.
Please do ask if my question is not clear, i am not from a english speaking country.
Here is some code.
ALuint AudioController::PlayStream(const string& asset)
{
//attach to a thread
[NSThread detachNewThreadSelector:(SEL)selector toTarget:(id)selfwithObject:(id)argument]
}
void AudioController::RotateThread(const string& soundKey)
{
}
As you can see how do i pass the RotateThread method as a selector to the "detachNewThreadSelector" and also where do i get the self pointer.
Any help much appreciated.
Thanks
You can't do this. It isn't as a simple as "Where do I get the self pointer?" The actual question is, "Where do I get something that can respond to messages?" Because a C++ class can't.
Objective-C classes, objects and methods are completely different things from C++ classes, objects and methods. The fact that the two languages use the same terminology and use the things for similar purposes confuses a lot of people, but to be clear: They are totally different things that work in very different ways in the two languages. Case in point: C++ methods are simply called rather than dispatched based on a selector like Objective-C methods. And C++ classes aren't even objects.
You have two real options here:
Create an Objective-C class that has the behavior you want.
Use a C++ concurrency solution.
you may not use c++ object in this manner (as an argument to this NSThread method). if your case is simple (read: few interfaces declared), then you can create a utility (objc) class to handle the message, and to then pass the argument back to the AudioController instance. illustration:
(non-compiled pseudo code follows)
namespace pseudo_object {
template <typename> class reference_counted;
}
#interface MONAudioControllerWorker : NSObject
{
pseudo_object::reference_counted<AudioController> audioController_;
std::string asset_;
}
+ (MONAudioControllerWorker *)newMONAudioControllerWorkerWithAudioController:(pseudo_object::reference_counted<AudioController>&)audioController asset:(const std::string&)asset;
- (void)secondaryWorker;
#end
#implementation MONAudioControllerWorker
+ (MONAudioControllerWorker *)newMONAudioControllerWorkerWithAudioController:(pseudo_object::reference_counted<AudioController>&)audioController asset:(const std::string&)asset
{
/* ... */
}
- (void)secondaryWorker
{
NSAutoreleasePool * pool([NSAutoreleasePool new]);
audioController_->RotateThread(asset_);
[pool release];
}
#end
/* static */
ALuint AudioController::PlayStream(pseudo_object::reference_counted<AudioController>& This, const string& asset)
{
/* attach to a thread */
MONAudioControllerWorker * controller = [MONAudioControllerWorker newMONAudioControllerWorkerWithAudioController:This asset:asset];
[NSThread detachNewThreadSelector:#selector(secondaryWorker) toTarget:controller withObject:0];
[controller release];
}
sometimes it is just easier to create an objc class which may contain a simplified (generic) interface for this purpose (i.e. reusable beyond this object), or to use more traditional threading routines (pthreads). if this is the only case in the project, then it should be fine. otherwise, you end up with many utility classes/symbols and much more to maintain. illustration:
#interface MONAudioControllerWrapper : NSObject
{
AudioController audioController_;
std::string asset_;
}
+ (MONAudioControllerWrapper *)newMONAudioControllerWrapperWithAsset:(const std::string&)asset;
- (void)playStream;
#end
#implementation MONAudioControllerWrapper
+ (MONAudioControllerWrapper *)newMONAudioControllerWrapperWithAsset:(const std::string&)asset
{
/* ... */
}
- (void)secondaryWorker
{
NSAutoreleasePool * pool([NSAutoreleasePool new]);
audioController_->RotateThread(asset_);
[pool release];
}
- (void)playStream
{
[NSThread detachNewThreadSelector:#selector(secondaryWorker) toTarget:self withObject:0];
}
#end
As others have said, you can't use detachThreadWithSelector: passing a C++ object as a target or using a C++ method as the selector.
You have two strategies:
wrap the object and selector with an OBjective-C object and selector e.g.
myAudioControllerWrapper = [[OCAudioControllerWrapper alloc] initWithRealController: this];
// need some code to release once thread is complete
[NSThread detachNewThreadSelector: #selector(wrapperSelector:) target: myAudioControllerWrapper withObject: soundKeyAsNSObject];
and your wrapper selector looks like:
-(void) wrapperSelector: (id) key
{
cppController->rotateThread([key cppObject]);
}
Use some other thread mechanism more in keeping with the C++ paradigm. Grand Central Dispatch might be the one if your platform supports it.

passing object from iphone app to library in object C

I've one application and two lib files. Application initialize a class object which need to pass to another class which is in the library. How can i do that? Here is what i did but it just crash
mainClass.h
#interface mainUIDelegate: NSObject<UIApplicationDelegate>
{
bla bla...
myCppClass myCppObject;
}
mainClass.mm
-(void)viewDidLoad{
myCppObject = new myCppClass();
}
-(void)initObject:(id)sender
{
prefTableViewController *prefs = [[prefTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
prefs.myCppObject = myCppObject;
}
library 1 (myCppClass.h) (with cpp class object)
class myCppClass{
int a;
}myCppClass;
library 2 (prefTableViewUI.h)
#interface prefTableViewController:UITableViewController{
myCppClass myCppObject;
}
#property (nonatomic, assign) myCppClass myCppObject;
Can someone please let me know how can i pass such object? I've just a month experience in object C.
Indeed more information is needed on what/where exactly crash. Not knowing how your class is defined, I'd say the property looks suspicious. You want to try to create a method first, say -[prefTableViewController setMyCppObject:] with the argument type being myCppClass*, and then implement the method as myCppObject = *argument.
(One sideway suggestion, though purely stylistic matter: Upper-casing the first letter of your Objective-C class name will help tell which is which)
I resolved this, the problem was lying in sythensizing the object. I had forgot to synthesize the object.