0

我试图在 Objective-C 中包装一个 C API,但在 objc_release 中得到 EXC_BAD_ACCESS。

字段.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;
};

字段.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

测试:

SCField *field = [[SCField alloc] initWithTitle:@"Hello world!"];
NSLog(@"%@\n", [field title]);
[field release];

在我发布我的 SCField 实例之前,代码似乎工作正常。如果我删除标题和 setTitle: 实现,就好像我直接在 SCField 中存储一个 NSString* 代码工作正常(我也尝试在 @property 中分配而不是复制 - 不走运)。我究竟做错了什么?

4

2 回答 2

3

我认为问题在于调用UTF8String会给你自动释放的内存(根据文档)。

而不是使用realloc()in sc_set_title(),只是malloc()一个新的缓冲区并复制它。此外,realloc()无论如何,您的参数都不正确,因此它可能最终成为无操作。你需要分配strlen(title) + 1;sizeof 不会为您做任何事情,因为您只是要求编译器给您 1 ( sizeof(char)) * 4 个字节(sizeof(title)- 一个指针)。

于 2012-12-12T09:08:49.407 回答
0

使用getCString:maxLength:encoding:. 要获取缓冲区的字符串长度(以字节为单位),请使用lengthOfBytesUsingEncoding:(takes O(n) time) 或maximumLengthOfBytesUsingEncoding:(takes O(1) time)。

于 2012-12-12T09:16:00.057 回答