Wrapping a C API in Objective-C - objective-c

I'm trying to wrap a C API in Objective-C but am getting EXC_BAD_ACCESS in objc_release.
Field.h:
#ifdef __cplusplus
extern "C" {
#endif
struct sc_field
{
char *title;
};
typedef struct sc_field sc_field_t;
sc_field_t* sc_create_field();
void sc_destroy_field(sc_field_t *field);
const char* sc_get_title(const sc_field_t *field);
void sc_set_title(sc_field_t *field, const char *title);
#ifdef __cplusplus
}
#include <string>
class Field
{
public:
explicit Field();
virtual ~Field();
std::string title() const;
void setTitle(const std::string &title);
private:
class Private;
Private *d;
};
Field.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Field.h"
sc_field_t* sc_create_field()
{
sc_field_t *field = (sc_field_t*)malloc(sizeof(sc_field_t));
field->title = (char*)calloc(1, sizeof(char));
return field;
}
void sc_destroy_field(sc_field_t *field)
{
if (field)
{
free(field->title);
free(field);
}
}
const char* sc_get_title(const sc_field_t *field)
{
if (!field)
{
fprintf(stderr, "%s: fatal error, field is NULL\n", __FUNCTION__);
return NULL;
}
return field->title;
}
void sc_set_title(sc_field_t *field, const char *title)
{
if (!field)
{
fprintf(stderr, "%s: fatal error, field is NULL\n", __FUNCTION__);
return;
}
field->title = (char*)realloc(field->title, sizeof(char) * sizeof(title));
strcpy(field->title, title);
}
SCField.h:
#import "Field.h"
#import <Foundation/Foundation.h>
#interface SCField : NSObject
{
#private
sc_field_t *field;
}
#property (nonatomic, copy) NSString *title;
- (id)init;
- (id)initWithTitle:(NSString *)title;
- (void)dealloc;
#end
SCField.m:
#import "SCField.h"
#implementation SCField
#synthesize title;
- (id)init
{
self = [super init];
if (self)
{
field = sc_create_field();
}
return self;
}
- (id)initWithTitle:(NSString *)aTitle
{
self = [self init];
if (self)
{
[self setTitle:aTitle];
}
return self;
}
- (void)dealloc
{
sc_destroy_field(field);
[super dealloc];
}
- (NSString *)title
{
return [NSString stringWithUTF8String:sc_get_title(field)];
}
- (void)setTitle:(NSString *)aTitle
{
sc_set_title(field, [aTitle UTF8String]);
}
#end
Test:
SCField *field = [[SCField alloc] initWithTitle:#"Hello world!"];
NSLog(#"%#\n", [field title]);
[field release];
The code seems to work fine until I release my SCField instance. If I remove the title and setTitle: implementations as if I were storing an NSString* directly in the SCField the code works fine (I tried assign instead of copy in the #property, too - no luck). What am I doing wrong?

I think the issue is that calling UTF8String will give you memory that will be autoreleased (according to the documentation).
Rather than using realloc() in sc_set_title(), just malloc() a new buffer and copy it. Also, your realloc() parameters are incorrect anyway, so it probably ends up being a no-op. You need to allocate strlen(title) + 1; sizeof won't do anything for you since you're just asking the compiler to give you 1 (sizeof(char)) * 4 bytes (sizeof(title) - a pointer).

Use getCString:maxLength:encoding:. To get length of string in bytes for a buffer, use lengthOfBytesUsingEncoding: (takes O(n) time) or maximumLengthOfBytesUsingEncoding: (takes O(1) time).

Related

OpenCV K-Nearest Implementation with Objective-C++ throws EXC_BAD_ACCESS

I have an issue when implementing OpenCV's K-Nearest to Objective-C++
Below is my sample code for implementation:
BridgeClass.h
#ifndef BridgeClass_h
#define BridgeClass_h
#include <Foundation/Foundation.h>
#interface BridgeClass : NSObject
- (void)testFunction;
#end
#endif
BridgeClass.mm
using namespace ml;
typedef KNearest KNN;
#implementation BridgeClass{
KNN* kNearest;
}
- (id) init {
self = [super init];
if (self) {
kNearest = KNN::create();
}
return self;
}
- (void) testFunction {
BOOL test = kNearest->isTrained();
NSLog(#"Test: %d", test);
}
But when I called testFunction, it shows error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x400000048)
What is the problem with my implementation?

how to create and allocate a C buffer as part of an objective C class

best to explain with an example:
in my AudioItem.h
#define ITEM_CAPACITY 100
typedef struct DataStruct {
void * content;
UInt32 size;
} DataStruct;
typedef DataStruct *DataStructRef;
#interface AudioItem : NSObject
{
DataStructRef data;
}
#property (assign, readwrite) DataStructRef data;
in AudioItem.m
#synthesize data;
-(id)initWithID:(NSString *)itemID
{
self = [super init];
data->content = malloc(ITEM_CAPACITY);
return self;
}
The above code looks a lot like this one, but I get a BAD_EXEC_ERROR.. how come? The reason why I would like to use a C buffer rather than some NSMutableData or whatever is b/c I've tried using NSMutableData and I feel like it's slowing down my real time application
it fails because data is a null pointer when you set its content.
the easy way to do this is:
enum { ITEM_CAPACITY = 100 };
typedef struct DataStruct {
char content[ITEM_CAPACITY];
UInt32 size;
} DataStruct;
#interface AudioItem : NSObject
{
#private
DataStruct data;
}
#implementation AudioItem
- (id)initWithID:(NSString *)itemID
{
self = [super init];
if (0 == self) return;
data.size = ITEM_CAPACITY;
return self;
}

c struct implementation in iOS

SSharedAppState.h
#import <Foundation/Foundation.h>
enum {
SharedCompletedStepNone = 0,
SharedCompletedStepOne = 1 << 0,
SharedCompletedStepTwo = 2 << 1,
SharedCompletedStepThree = 3 << 2
};
typedef NSUInteger SharedCompletedSteps;
#interface SSharedAppState : NSObject
{
struct {
unsigned int sharedCompletedStepMask:3;
} _appFlags;
}
#property (assign, nonatomic) SharedCompletedSteps sharedCompletedStep;
+(id)sharedInstance;
#end
SSharedAppState.m
#import "SSharedAppState.h"
#pragma mark - C functions
#pragma mark - Interface Extension
typedef struct _appFlags AppFlags;
#interface SSharedAppState ()
#property (unsafe_unretained, nonatomic) AppFlags *appFlags;
-(void *)newAppFlags;
#end
#pragma mark - Implementation
#implementation SSharedAppState
#synthesize appFlags;
#pragma mark - Iniitalizer
-(id)init
{
self = [super init];
if (self) {
// appFlags = (AppFlags *)malloc(sizeof(_appFlags));
appFlags = (AppFlags *)newAppFlags();
appFlags->sharedCompletedStepMask = 0;
appFlags.sharedCompletedStepMask = 0;
}
return self;
}
+(SSharedAppState *)sharedInstance
{
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
#pragma makr - Struct _appFlags
-(void *)newAppFlags
{
AppFlags *instance = (AppFlags *)malloc(sizeof(_appFlags));
return instance;
}
#end
Questions
appFlags = (AppFlags *)newAppFlags();
gives implicit declaration of function newAppFlags is invalid in C99
appFlags->sharedCompletedStepMask = 0;
appFlags.sharedCompletedStepMask = 0;
Incomplete definition of type 'struct _appFlags'
Member reference type 'AppFlags *' (aka 'struct _appFlags *') is a pointer; maybe you meant to use '->'?
Gives following warnings and error.
These is my first time to post questions here so please advice on html or editing. Thankyou!
When you write like this
struct {
unsigned int sharedCompletedStepMask:3;
} _appFlags;
you are declaring a variable _appFlags of an unnamed struct.
you probably meant
struct _appFlags {
unsigned int sharedCompletedStepMask:3;
};
or you could write
typedef struct _appFlags {
unsigned int sharedCompletedStepMask:3;
} AppFlags;

Properly use Objective C++

I'm coding an app for iOS and I recently #included a C++ header file in an Objective C implementation (.m) file. I changed the extension from .m to .mm and expected everything to run smoothly.
Unexpectedly I got multiple compiler errors in the .h file of my C++ class.
Such as: "C++ requires a type specifier for all declarations" and "Duplicate member...".
Does anyone know what could be causing this?
Edit - I've added the C++ header file for context:
#ifndef __CAAudioUnitOutputCapturer_h__
#define __CAAudioUnitOutputCapturer_h__
#include <AudioToolbox/ExtendedAudioFile.h>
/*
Class to capture output from an AudioUnit for analysis.
example:
CFURL fileurl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/tmp/recording.caf"), kCFURLPOSIXPathStyle, false);
CAAudioUnitOutputCapturer captor(someAU, fileurl, 'caff', anASBD);
{
captor.Start();
...
captor.Stop();
} // can repeat
captor.Close(); // can be omitted; happens automatically from destructor
*/
class CAAudioUnitOutputCapturer {
public:
enum { noErr = 0 };
CAAudioUnitOutputCapturer(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription &format, UInt32 busNumber = 0) :
mFileOpen(false),
mClientFormatSet(false),
mAudioUnit(au),
mExtAudioFile(NULL),
mBusNumber (busNumber)
{
CFShow(outputFileURL);
OSStatus err = ExtAudioFileCreateWithURL(outputFileURL, fileType, &format, NULL, kAudioFileFlags_EraseFile, &mExtAudioFile);
if (!err)
mFileOpen = true;
}
void Start() {
if (mFileOpen) {
if (!mClientFormatSet) {
AudioStreamBasicDescription clientFormat;
UInt32 size = sizeof(clientFormat);
AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, mBusNumber, &clientFormat, &size);
ExtAudioFileSetProperty(mExtAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
mClientFormatSet = true;
}
ExtAudioFileWriteAsync(mExtAudioFile, 0, NULL); // initialize async writes
AudioUnitAddRenderNotify(mAudioUnit, RenderCallback, this);
}
}
void Stop() {
if (mFileOpen)
AudioUnitRemoveRenderNotify(mAudioUnit, RenderCallback, this);
}
void Close() {
if (mExtAudioFile) {
ExtAudioFileDispose(mExtAudioFile);
mExtAudioFile = NULL;
}
}
~CAAudioUnitOutputCapturer() {
Close();
}
private:
static OSStatus RenderCallback( void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
if (*ioActionFlags & kAudioUnitRenderAction_PostRender) {
CAAudioUnitOutputCapturer *This = (CAAudioUnitOutputCapturer *)inRefCon;
static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8);
if (This->mBusNumber == inBusNumber && !(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)) {
OSStatus result = ExtAudioFileWriteAsync(This->mExtAudioFile, inNumberFrames, ioData);
if (result) DebugMessageN1("ERROR WRITING FRAMES: %d\n", (int)result);
}
}
return noErr;
}
bool mFileOpen;
bool mClientFormatSet;
AudioUnit mAudioUnit;
ExtAudioFileRef mExtAudioFile;
UInt32 mBusNumber;
};
#endif // __CAAudioUnitOutputCapturer_h__
Unfortunately, if you just start making classes .mm, any class that uses that .mm's header will also need to become .mm. If you continue to just change your class extensions, you will eventually make the whole project Objective-c++. If that is your intention, then you can just change your build settings to compile for Objective-c++ (which could be a house of pain for you).
However, if you use some header magic, you will avoid a lot of hassle. Just make sure to change your Compile sources as build property to According to file type before compiling.
Here's something I did with a wrapper class I wrote to isolate a c++ class from the rest of my Objective-c classes. The c++ class is MyClass.
MyClassWrapper.h
//declare c++ impl for Obj-C++
#ifdef __cplusplus
class CppPlanterModel;
namespace com{namespace company{namespace mypackage {class MyClass;}}}
typedef com::company::mypackage::MyClass CppMyClass;
#endif
//declare obj-c impl
#ifdef __OBJC__
#ifndef __cplusplus
typedef void CppMyClass;
#endif
#endif
#interface MyClassWrapper : NSObject {
CppMyClass* _myClass;
}
//etc etc
#end
MyClassWrapper.mm
#include "MyClass.h"
using namespace com:company:mypackage;
class CppMyClass : public MyClass {
CppMyClass() {};
~CppMyClass() {};
//other stuff you might like to have
};
#implementation MyClassWrapper
//etc etc
#end
Here's another thing I did with a different header to handle sharing extern stuff:
Something.h
#ifdef __cplusplus
#define FV_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define FV_EXTERN extern __attribute__((visibility ("default")))
#endif
FV_EXTERN const int kMyInt;
FV_EXTERN int GetAnotherInt(...);
I recommend reading this blog entry about wrapping c++ (which also has links to other blog entries of a similar topic): http://robnapier.net/blog/wrapping-c-take-2-1-486
following the code at Rob Napier's blog I did it for CAAudioUnitOutputCapturer.
Thought I would share it to save other folks time.
RNWrap.h
//
// RNWrap.h
//
// ObjC wrapper for Wrap.cpp
//
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AudioUnit/AudioUnit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
struct RNWrapOpaque;
#interface RNWrap : NSObject {
struct RNWrapOpaque *_cpp;
}
- (id) initWithAudioUnit:(AudioUnit) au andURL:(CFURLRef) outputFileURL andAudioFileTypeID:(AudioFileTypeID) fileType andAudioStreamBasicDescription: (const AudioStreamBasicDescription) asbd;
- (void) Start;
- (void) Close;
- (void) Stop;
#end
RNWrap.mm
//
// RNWrap.mm
// Objective C++ Wrapper Class for CAAudioUnitOutputCapturer.h
//
// Created by Pier 23/10/12
// Copyright 2012 DreamUpApps. All rights reserved.
//
#import "RNWrap.h"
#import "CAAudioUnitOutputCapturer.h"
#interface RNWrap ()
#property (nonatomic, readwrite, assign) RNWrapOpaque *cpp;
#end
#implementation RNWrap
#synthesize cpp = _cpp;
struct RNWrapOpaque
{
public:
RNWrapOpaque(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription format) : outputCapturer(au, outputFileURL, fileType, format, 0) {}; // note added bus number = 0 at the end
CAAudioUnitOutputCapturer outputCapturer;
};
- (id)initWithAudioUnit:(AudioUnit) au andURL:(CFURLRef) outputFileURL andAudioFileTypeID:(AudioFileTypeID) fileType andAudioStreamBasicDescription: (const AudioStreamBasicDescription) format
{
self = [super init];
if (self != nil)
{
self.cpp = new RNWrapOpaque(au, outputFileURL, fileType, format);
}
return self;
}
- (void)dealloc
{
delete _cpp;
_cpp = NULL;
//[super dealloc];
}
- (void) Start
{
self.cpp->outputCapturer.Start();
}
- (void) Stop
{
self.cpp->outputCapturer.Stop();
}
- (void) Close
{
self.cpp->outputCapturer.Close();
}
#end
You use it like this in your class.
- (void) captureInAppAudio:(AudioUnit) auToCapture
{
AudioStreamBasicDescription destFormat;
memset( &destFormat, 0, sizeof(AudioStreamBasicDescription) );
destFormat.mSampleRate = 44100;
destFormat.mFormatID = kAudioFormatLinearPCM;
destFormat.mFormatFlags = ( kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagIsBigEndian );
destFormat.mBytesPerPacket = 2;
destFormat.mFramesPerPacket = 1;
destFormat.mBytesPerFrame = 2;
destFormat.mChannelsPerFrame = 1;
destFormat.mBitsPerChannel = 16;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
soundPath = [documentsDirectory stringByAppendingString:#"/recording.caf"] ;
CFURLRef fileurl = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)soundPath, kCFURLPOSIXPathStyle, false);
captor = [[RNWrap alloc] initWithAudioUnit:auToCapture andURL:fileurl andAudioFileTypeID:'caff' andAudioStreamBasicDescription:destFormat];
[captor Start];
}
Hope this helps someone else out there!
Pier.

static behaviour->objective C

I have this static declaration of m_pData=1099656 in a class.
In main NSLog(#"Testing:%d",m_pData);
Its printing me 0.
How to get the same value of m_pData in the class in the main function too.
I cant use obj.m_pData or obj->m_pData to acces the variable.
EDITED:
test2.m
----------
#import <Foundation/Foundation.h>
#import "data_derived.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
data* dat = [data alloc];
requestSession* session = [requestSession alloc];
[session init];
[dat TxCreateImage:RM_REQUEST_SESSION];
NSLog(#"Testing:%d",m_pData); //the static variable is not printing the value its holding.Its printing Zero.If printed the same variable inside the class it gives some numbers.
[dat dataBuffer:&m_pData withLen:&m_uDataSize]; //here the actual values of static values are not passed.when printed both of them contains zero values.
[pool drain];
return 0;
}
data.h
--------
#import <Foundation/Foundation.h>
#import "remote.h"
static int m_nMessageId; //Message ID
static int m_uSessionId; //Session ID
static int m_chSequenceChar; //Sequence ID
static int* m_pData; //Integer buffer to carry data
static int m_uDataSize; //Datasize
#interface data : NSObject {
#public
}
- (id)initWithID:(int) uMessageId withData:(id)pData withSize:(size_t) uDataSize;
+ (void)initialize;
- (void)dealloc;
- (id) dataBuffer:(int**)m_Data withLen:(int**)uLen;
- (BOOL) TxCreateImage:(int)messageId;
#end
data.m
---------
#import "data.h"
#define ENCODED_MSG_DATA_OFFSET 8
#implementation data
+ (void)initialize
{
m_uSessionId = 0;
m_chSequenceChar= 0;
// Initialize values from derived class
m_nMessageId = 0;
m_pData = 0;
m_uDataSize = 0;
}
- (id) initWithID:(int) uMessageId withData:(id)pData withSize:(size_t) uDataSize
{
if(self=[super init])
{
// Initialize the member variables
m_uSessionId = 0xFF;
m_chSequenceChar= 10;
// Initialize values from derived class
m_nMessageId = uMessageId;
m_pData = (int*)pData;
m_uDataSize = (int)uDataSize;
}
NSLog(#"Data size:%d",uDataSize);
NSLog(#"m_pData:%d",m_pData);
NSLog(#"pData:%d",pData);
return self;
}
- (id) dataBuffer:(int**)m_Data withLen:(int**)uLen
{
if ( m_uDataSize <= RMH_MAX_ENCODED_LENGTH )
{
int abBigEndian[RMH_MESSAGE_MAX_SIZE];
memcpy(abBigEndian,m_Data,m_uDataSize);
NSLog(#"m_Data:%d",*m_Data);
NSLog(#"abBigEndian:%d",abBigEndian);
uLen += ENCODED_CRC_BYTE_LEN + 1;
NSLog(#"%d",*uLen);
}
NSLog(#"END!");
return self;
}
- (BOOL) TxCreateImage:(int)messageId
{
char pData[4096];
sprintf(pData,"%x %d %d %d %x",ASCII_STX,m_uSessionId,m_chSequenceChar,m_nMessageId,ASCII_ETX); //uLen = ENCODED_MSG_DATA_OFFSET;
NSLog(#"%s",pData);
return YES;
}
- (void)dealloc
{
[super dealloc];
}
#end
data_derived.h
---------------------
#import <Foundation/Foundation.h>
#import "data.h"
#define DECLARE_RS232_NEWMSG(ClassID)\
enum \
{ \
ID = ClassID \
}; \
#interface requestSession : data {
#public
DECLARE_RS232_NEWMSG(RM_REQUEST_SESSION);
struct RMH_REQUEST_SESSION_MSG st;
}
-(id)init;
-(void)dealloc;
#end
data_derived.m
---------------------
#import "data_derived.h"
#implementation requestSession
- (id)init
{
size_t asize = sizeof(st);
st.uDeviceID = RS232_PROTOCOL_DEVICE_ID;
st.uProtocolVersion = RS232_VERSION;
memset(st.uReserved,0x00,sizeof(st.uReserved));
NSLog(#"Address of the structure:%d",&st);
self=[super initWithID:ID withData:(id)&st withSize:asize];
if (self) {
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
#end
Don't place your static members in .h file. Move them to data.m.
Also about static keyword - in C (and Objective C, which is clear superset to C), when using static with global variables (like you do), it only indicates that this variables will be local to the file you declared these variable in. So global variables anyway have only one instance, with static modifier or without. If you don't use static, then you can access these variables from other files with external declaration, like:
// file1.m
int variable = 4;
// file2.m
external int variable; // variable == 4
That's why your code is printing you 0. m_pData in test2.m is not the same m_pData you have in data.m. Without static modifier you would get a linker error.
And you might want to write getters/setters for static members. Like:
+ (int *)pData {
return m_pData; // or smth like memcpy
}