C++ vector as member of Objective C class doesn't retain value - objective-c++

So I've got an Objective C class that will implement the NSTableViewDataSource protocol to display a list of audio output devices. I'm calling a C++ class that returns device information as a std::vector of C structs of the form
typedef struct DeviceInfo {
AudioDeviceID devID;
char name[128];
int nInputChannels;
int nOutputChannels;
} DeviceInfo;
The Objective C class is
#interface PreferencesViewController : NSObject <NSTableViewDataSource> {
AudioOutputController *audioOutputController_;
vector<DeviceInfo> audioOutputDevices_;
}
- (void)setAudioOutputController:(AudioOutputController *)controller;
- (void)updateDeviceList;
- (IBAction)buttonPressed:(id)sender;
#end
The main app controller sets the PreferencesViewController's AudioOutputController member (the C++ class), then calls updateDeviceList(), which tells the AudioOutputController to query the available audio devices and return a vector of DeviceInfo structs
- (void)updateDeviceList {
/* Update the list of currently connected devices and return device information */
audioOutputController_->setAvailableDevices();
audioOutputDevices_.clear();
audioOutputDevices_ = audioOutputController_->getAvailableDevices();
for (int i = 0; i < audioOutputDevices_.size(); i++) {
printf("Device %d: %s\n", i, audioOutputDevices_[i].name);
printf("\t%d Output Channels\n", audioOutputDevices_[i].nOutputChannels);
}
}
This all works completely fine and prints the available audio devices, but the vector of structs doesn't seem to retain its value outside updateDeviceList(), so I see an empty vector when I try to access it in the NSTableViewDataSource protocol methods. If I try to just print the size of the vector in an IBAction method, for example
- (IBAction)buttonPressed:(id)sender {
printf("audioOutputDevices_.size() = %lu\n", audioOutputDevices_.size());
}
it says the vector is empty. I'm new to combining C++ and Objective C, so any help is greatly appreciated.
Edit: something else peculiar. If I call PreferencesViewController's updateDeviceList() method from the AppDelegate's applicationDidFinishLaunching(), as follows:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
audioOutputController_ = new AudioOutputController();
preferences_ = [[PreferencesViewController alloc] init];
[preferences_ setAudioOutputController:audioOutputController_];
[preferences_ updateDeviceList:self];
}
#end
then I get the problem stated above, with the C++ vector not retaining its value. If I instead make updateDeviceList() an IBAction callback for an interface button, then when I call it it retains its value and the device information gets added to the table.

I believe (from a similar experience of mine) that during application startup the C++ constructor of vector<DeviceInfo> audioOutputDevices_ is somehow called again, which clears it.

Related

iOS -- use macros to forward a bunch of messages?

ForwardInvocation does exist, but it is slow and has the annoying problem of compiler warnings. So that got me to thinking -- is there a way to use macroes to quickly implement a bunch of getter methods that get the property in question from another object?
For example, if I have a Car object, it might want to implement the following:
Car.h:
#class SparkPlug;
#class Engine;
. . .
-(int) nPistons;
-(float) horsepower;
-(SparkPlug*) sparkPlug;
Car.m:
. . .
-(int) nPistons {
return self.engine.nPistons;
}
-(float) horsepower {
return self.engine.horsepower;
}
-(SparkPlug*) sparkPlug {
return self.engine.sparkPlug;
}
Question -- would it be possible to set up some macroes so that by making one change somewhere, I could add another such method to both the header and implementation files?
e.g. MagicForwardingMacro (nPistons, int, engine);
Ideally, in such a way that the macroes would be reusable if I later wanted to later use a similar strategy to get the firstName, lastName, placeOfBirth, and dateOfBirth properties of a Person from his or her birthCertificate.
The easiest way is probably to add the methods dynamically:
Add the properties to a category so the compiler doesn't complain too much.
Clone a suitable IMP in +[NSObject resolveInstanceMethod:]. You'll need to poke the Objective-C runtime.
Elaborating on the second step:
For each type, add a method like
-(int)getEngineInt {
return (int()(id,SEL))(objc_msgSend)(engine, _cmd);
}
Note that for structs you need objc_msgSend_stret and for floats/doubles you might need objc_msgSend_fpret (I think you only need it on i386; not sure about AMD64). The easy hack to support both the simulator and device is something like (I forget the macro name GCC uses...)
#if __i386
#define objc_msgSend_fpret objc_msgSend
#endif
Now to implement +resolveInstanceMethod:, you need to know the class you're forwarding to ahead of time. Let's say it's Engine.
+(BOOL)instancesRespondToSelector:(SEL)name
{
return [Engine instancesRespondToSelector:name];
}
+(BOOL)resolveInstanceMethod:(SEL)name
{
// Do we want to super-call first or last? Who knows...
if ([super resolveInstanceMethod:name]) { return YES; }
// Find the return type, which determines the "template" IMP we call.
const char * returntype = [Engine instanceMethodSignatureForSelector:name].methodReturnType;
if (!returnType) { return NO; }
// Get the selector corresponding to the "template" by comparing return types...
SEL template = NULL;
if (0 == strcmp(returntype,#encode(int))
{
sel = #selector(getEngineInt);
}
else if (0 == strcmp(Returntype,#encode(float))
{
...
}
if (!sel) { return NO; }
Method m = class_getInstanceMethod(self,template);
return class_addMethod(self, name, method_getImplementation(m), method_getTypeEncoding(m));
}
Alternatively, there's a slightly undocumented method -forwardingTargetForSelector: which may be fast enough for your needs.
EDIT: Alternatively, you can loop over the properties/methods dynamically. There doesn't appear to be an obvious way to introspect categories, but you can define them in a protocol, do something like #interface Engine:NSObject<Engine> ... #interface Car(DynamicEngine)<Engine> and use objc_getProtocol("Engine") and then protocol_copyMethodDescriptionList()/protocol_copyPropertyList() to get the methods, and then add the getters. I'm not sure if properties are added to the "method description list". Also note that the "copy" functions do not copy methods/properties from superclasses, which (in this case) is what you want.
Sadly, I don't think Objective-C 2.0 properties will work for you because I don't think you can specify any kind of forwarding in the property declaration.
You can't have one macro that will insert text in two different places. However, you can use two macros like so:
//This could also take the third argument and discard it, if you like
#define FORWARDI(type, prop) - (type)prop;
#define FORWARDM(type, prop, owner) - (type)prop { return owner.prop; }
//In the header...
FORWARDI(float, nPistons)
//In the implementation...
FORWARDM(float, nPistons, self.engine)
If you don't mind the methods not showing up in the header file (for example, if you will only use these methods inside the class's implementation itself), you can just as well use the implementation file macro by itself.
This is agnostic to the type of the owner, but it should work with any expression.
I'm getting close to what I want. Some nagging details remain:
ForwardingInclude.h:
// no include guard; we want to be able to include this multiple times
#undef forward
#ifdef IMPLEMENTATION
#define forward(a, b, c) -(a) b { return [[self c] b]; }
#else
#define forward(a, b, c) -(a) b;
#endif
CarForwarding.h:
// again, no include guard
#include ForwardingInclude.h
forward(int, nPistons, engine)
forward(SparkPlug* sparkPlug, engine)
Car.h:
#interface Car: SomeSuperclass {
// some ivars
}
. . .
#include CarForwarding.h
Car.m:
. . .
#implementation Car
#define IMPLEMENTATION
#include CarForwarding.h
The nagging details:
1) I don't like that #define IMPLEMENTATION line. I want CarForwarding.h to somehow automatically detect whether or not it is currently being included inside an implementation.
2) It would be waaaaaay cool if I could have the stuff defined in the forwarding file somehow also appear in human-readable form in the header. Or better yet -- write the "forward" definitions directly into the Car.h file somehow, so I don't need the CarForwarding.h file at all.

Using/storing an array of floats in Cocoa

In c, if I wanted an array of floats (for instance) I would just define the fixed size and allocate it, and I could access each element for math operations. However, I want the ability to have my arrays be mutable since they will continually grow in size (as the app is running, and the array could easily surpass 10000+ elements) and the idea of NSMutableArray sounds great. However, (if I understand correctly) it only stores objects, I would have to wrap my numbers in NSNumber, and then put those into the array. That seems like a ridiculous amount of overhead to just store an array of floats (or doubles or integers).
On the other hand, I see that there are flout attributes for Core Data, but I don't see how I could access this in the same way ( array[index] ). Am I missing something here? Should all heavy-lifting math just be done in fixed-sized c arrays, are there ways of using the foundation classes that I haven't stumbled upon, or are there ways of accessing core data objects like one would access an array?
you aren't missing anything here; there's not a formal objc interface for arrays of c scalar types.
the simple way (as westsider mentioned) is to use std::vector, and then implement serialization/deserialization using a mechanism such as CF/NS-Data.
you could wrap std::vector in an objc interface, if you wanted:
/* MONDoubleArray.h */
/* by using pimpl, i'm assuming you are not building everything as objc++ */
struct t_MONDoubleArray_data;
#interface MONDoubleArray : NSObject < NSCoding, NSCopying, NSMutableCopying >
{
t_MONDoubleArray_data* data;
}
- (double)doubleAtIndex;
- (void)setDoubleAtiIndex:(double)index;
- (NSUInteger)count;
/*...*/
#end
/* MONDoubleArray.mm */
struct t_MONDoubleArray_data {
std::vector<double> array;
};
#implementation MONDoubleBuffer
- (id)init
{
self = [super init];
if (0 != self) {
/* remember your c++ error handling (e.g., handle exceptions here) */
array = new t_MONDoubleArray_data;
if (0 == array) {
[self release];
return 0;
}
}
return self;
}
/*...more variants...*/
- (void)dealloc
{
delete array;
[super dealloc];
}
- (NSData *)dataRepresentationOfDoubleData { /*...*/ }
- (void)setDoubleDataFromDataRepresentation:(NSData *)data { /*...*/ }
/*...*/
#end
then, you'd have accomplished objc serialization without hassle.
there's also a way to use a CF/NS_MutableArray for scalars, using pointer (or narrower) sized entries:
#interface MONFloatBuffer : NSObject
{
NSMutableArray * floats;
}
#end
#implementation MONFloatBuffer
- (id)init
{
self = [super init];
if (0 != self) {
CFAllocatorRef allocator = 0; /* default */
CFIndex capacity = 0; /* resizable */
/* you could implement some of this, if you wanted */
const CFArrayCallBacks callBacks = { 0 /* version */ , 0 /* retain */ , 0 /* release */ , 0 /* copyDescription */ , 0 /* equal */ };
floats = (NSMutableArray*)CFArrayCreateMutable(allocator, capacity, &callBacks);
// now we can read/write pointer sized values to `floats`,
// and the values won't be passed to CFRetain/CFRelease.
}
return self;
}
#end
however, that would still fail to properly deserialize itself without customization. so... NSPointerArray would accomplish that more easily... but you still fixed to pointer sized values, so you have to write it yourself. which not terribly hard. the downside is the number of variants you may ultimately end up with.
I would avoid wrapping your floats in NSNumbers and using NSMutableArrays. As you say, this adds a ridiculous amount of overhead.
I would recommend using C++ Standard Template Library (STL) containers. In your case, vector would be the best.
Using STL will mean moving from Objective-C to Objective-C++ ... and it will require changing extensions of effected source files from .m to .mm, as well as adding #import to files that make use of std::vector.
Another approach would be to use an NSMutableData object - but you would probably end up doing more of the bookkeeping wrt appending data (floats).

shared static function in objective-c iphone?

I need to calculate from pricing based on some business rules and I do not want to duplicate this across several ViewControllers. Coming from a .Net world I would use a static method on a class to do this. What is a similar solution in Objective-C?
A class method most likely - ie. a function in the interface declared with a + at the start.
#implementation PriceCalculator
+ (float)calculatePrice:(float)param1 {
return param1*4.0;
}
#end
(and a similar #interface in a header file)
which is called like so:
price = [PriceCalculator calculatePrice:3.0];
If you don't need to override the behavior in subclasses, you can just write a C function, which is the equivalent of a static method in Java and C#. Otherwise, do as JosephH suggested, and write a class method. Here's his example rewritten as a C function:
float calculatePrice(float amount)
{
return amount * 4.0;
}
The function could be declared/implemented in the .h/.m pair of files for one of your classes if that's convenient, but you could also create a separate .h/.m pair that just contains C functions if you like.

How to "fake" ivars in an Obj-C category (iPhone)

Update:
iPhone OS 3.1 has associated objects. However, the iPhone simulator does not. If you want to test associated objects code in the simulator, you should file a bug.
See my SO question here.
rdar://7477326
Snow Leopard now has associated objects.
Is there a way to accomplish something similar without associated objects? (Specifically for the iPhone.)
I am pretty sure I saw something like this a while back, but I can't remember where. Something about turning any object into a KVC container.
objc_setAssociatedObject() and friends were added to iPhone OS 3.1, so if you have the option of targetting just 3.1+ devices you can in fact do the exact same thing as on Snow Leopard...
If you can't you can create a static dictionary of associations and monkey patch out NSObjects dealloc method. For various technical reasons this solution cannot be made to work correctly in the presence of GC (which is why apple added the association stuff), but since iPhone does not support GC that is a non-issue.
If you are just starting work on this project I highly recommend using the runtime functions and targeting 3.1 plus, but if that is not an option here is an example of how you do it.
LGAssociativeStorage.h:
#import <pthread.h>
#import <Foundation/Foundation.h>
#interface NSObject (LGAssociativeStorage)
#property (retain) id associatedObject;
#end
LGAssociativeStorage.mm
#import <objc/runtime.h>
#import "LGAssociativeStorage.h"
/* We are using STL containers because:
1) Using Objective C containers can cause deallocs which cause recursion issues
2) STL containers are high perf containers that don't introduce external code dependencies
Ideally one could include a thread safe map implementation, but I don't need one currently
*/
#include <map>
typedef std::map<id,id> idMap_t;
typedef std::pair<id,id> idPair_t;
static NSMutableDictionary * data = nil;
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
static IMP gOriginalNSObjectDealloc = nil;
static idMap_t associatedObjectMap;
static
void removeAssociatedObjectFromMap(id self) {
idMap_t::iterator iter = associatedObjectMap.find(self);
if( iter != associatedObjectMap.end() ) {
[iter->second release];
associatedObjectMap.erase(iter);
}
}
static
id newNSObjectDealloc(id self, SEL deallocSelector, ...) {
pthread_mutex_lock(&data_lock);
removeAssociatedObjectFromMap(self);
pthread_mutex_unlock(&data_lock);
return gOriginalNSObjectDealloc(self, deallocSelector);
}
static void initIfNecessary(void) {
if (!data) {
data = [[NSMutableDictionary alloc] init];
// The below line of code is abusive... in the future the Objective C runtime will use it as evidence
// that I am an unfit software engineer and take custody of all my code
gOriginalNSObjectDealloc = class_replaceMethod([NSObject class], #selector(dealloc), newNSObjectDealloc, "v#:");
}
}
#implementation NSObject (LGAssociativeStorage)
- (id) associatedObject {
id retval = nil;
pthread_mutex_lock(&data_lock);
initIfNecessary();
idMap_t::iterator iter = associatedObjectMap.find(self);
if( iter != associatedObjectMap.end() ) {
retval = iter->second;
}
pthread_mutex_unlock(&data_lock);
return retval;
}
- (void) setAssociatedObject:(id)object_ {
pthread_mutex_lock(&data_lock);
initIfNecessary();
removeAssociatedObjectFromMap(self);
[object_ retain];
associatedObjectMap.insert(idPair_t(self, object_));
pthread_mutex_unlock(&data_lock);
}
#end
You could always have them stored in a singleton.
There are no good ways to do this in a generic category.
You can easily add data for an object by having a global NSMutableDictionary that maps from any arbitrary NSObject to whatever data you want. The problem is there is no way to know when the object is deallocated, so you cannot tell (in general) when the data goes stale.
The only generic way to solve this is to use method swizzling to replace the NSObject dealloc method to report the deallocation of the object and release your associated data. I'm sure someone has done this, but its such a hideous hack it would be very hard to recommend as a valid appropach.
Now, if your objects in questions have some other way to monitor life cycle (ie, some deallocation hook, like a delegate objectWillClose method of some sort), then you can hook in to that to release your associated data and that would make the technique quite straight forward and legitimate.
I'll add an answer.
I found the original blog post, it was from Steve Degutis.
It basically involves replacing NSObject's methods for valueForUndefinedKey:, setValue:ForUndefinedKey:, and dealloc. Then using a static Dictionary to store any undefined keys.
Just about as nasty and fun as Louis's solution.
Notwithstanding concerns for concurrency issues, why not just use global variables ? Even using runtime objc_set/get AssociatedObject() methods aren't you passing a "global" static variable address in which case you still have concurrency issues wouldn't you?

How to call a method without an instantiated object

This is an objective-c question.
I would like to call a method in an object, but there is no instantiation of the object. Is this possible?
The method I want to call is not a class method.
You can't call a method on an object that doesn't exist. But you can call a method on a class even if you have no instantiated objects of that class. (That's what alloc is in #fbrereton's answer -- a class method).
Class methods are declared and defined with a + instead of a -, are called on the class rather than the instance, and cannot access self or any instance variables in the class (for reasons that should be obvious).
Unless the method is static you will not be able to do this. static routines in Objective-C will be prepended with a +. For example NSObject provides these two routines (among many):
+ (id)alloc; // static - an NSObject instance is not required
- (NSString*)description; // nonstatic - an NSObject instance is required
One would make the respective calls like so:
NSObject* result = [NSObject alloc];
NSString* desc = [result description];
Sorry to nit-pick Chris' terminology, but we don't call a method on an object in Objective-C, we send a message to an object. When you send a message, the runtime will look up the appropriate method and call it. The distinction matters.
Perhaps you just want a plain-old C function. If you don't want a class method, and you don't want an instance method, that appears to be your only option. Don't be afraid of using C functions in Objective-C. Every technique has its place.
You can indeed invoke an instance method without an instance, provided it is functionally a class method (that is, it accesses no instance variables). Here's an example:
/*
Compile with:
gcc -framework Foundation inst_method_without_inst.m -o inst_method_without_inst
*/
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Foo : NSObject {
}
- (BOOL)doSomethingWithThis:(NSString *)this;
#end
#implementation Foo
- (BOOL)doSomethingWithThis:(NSString *)this {
NSLog(#"Look, it's this: %#", this);
return YES;
}
#end
typedef BOOL (*my_sel_t)(id, SEL, NSString *);
int
main(void) {
Class cls = [Foo class];
SEL my_sel = #selector(doSomethingWithThis:);
Method m = class_getInstanceMethod(cls, my_sel);
// You could also use +[NSObject instanceMethodForSelector:] to get |m|,
// since |cls| is a kind of NSObject.
my_sel_t f = (my_sel_t)method_getImplementation(m);
BOOL result = f(nil, my_sel, #"Hello from an instanceless instance method invocation!");
NSLog(#"result: %d", (int)result);
return EXIT_SUCCESS;
}
You could get it to work even if the instance method accesses instance variables by allocating memory for it to work with (using either +alloc or class_getInstanceSize() plus malloc()) and passing a pointer to that memory as the first id argument to the implementation instead of nil.
While this is entertaining as an exercise, I can't think of a good reason to not just instantiate the class and use the standard messaging syntax and compiler support. In fact, the only reason we couldn't just do [(Foo *)nil doSomethingWithThis:#"BOO!"] here is that objc_msgSend() special-cases messages to nil with the result that NO is returned and nothing happens.