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()insc_set_title(), justmalloc()a new buffer and copy it. Also, yourrealloc()parameters are incorrect anyway, so it probably ends up being a no-op. You need to allocatestrlen(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).