EXC_BAD_ACCESS в вызове CFSocketSendData - PullRequest
2 голосов
/ 01 декабря 2011

Я использую экземпляр этого класса для передачи необходимых значений в функцию для отправки данных сокета:

@interface SsdpParameters : NSObject
{
    CFDataRef msg;
    CFDataRef addr;
    CFSocketRef sock;
}

@property CFDataRef msg;
@property CFDataRef addr;
@property CFSocketRef sock;

@end

Эта функция отвечает за отправку данных сокета:

-(void)SendSsdpResponse:(id)parameters
{
    SsdpParameters *params = parameters;
    CFDataRef msg = (CFDataRef)params.msg;
    CFDataRef addr = (CFDataRef)params.addr;
    CFSocketRef sock = (CFSocketRef)params.sock;

    CFSocketError err = CFSocketSendData (sock, addr, msg, 0);  // Program received signal:  "EXC_BAD_ACCESS".

    if (err)
    {
        NSLog(@"Error sending Valid Response");
    }
}

Эта функция устанавливает сокет и вызывает SendSsdpResponse после 1-секундной задержки:

- (void) sendValidResponses
{
    NSMutableString *message = nil;
CFSocketRef sock = [self newSSDPSendSocket];
if(sock != nil)
    {
        struct sockaddr_in SSDPaddr;
        memset(&SSDPaddr, 0, sizeof(SSDPaddr));
        SSDPaddr.sin_family=AF_INET;
        SSDPaddr.sin_addr.s_addr=inet_addr(SSDP_ADDRESS);
        SSDPaddr.sin_port=htons(SSDP_PORT);

        // Loop through list, sending SSDP
        for (NSString *aKey in list)
        {
            message = [[NSMutableString alloc] initWithString:@"NOTIFY * HTTP/1.1\r\n"];

        // Append more lines to message.

            CFDataRef addr = CFDataCreate(NULL, (const UInt8*)&SSDPaddr, sizeof(SSDPaddr));
            CFDataRef msg  = CFDataCreate(NULL, (const UInt8*)[message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);

            SsdpParameters *parameters = [[SsdpParameters alloc] init];
            parameters.msg = msg;
            parameters.addr = addr;
            parameters.sock = sock;

            [self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

            CFRelease(addr);
            CFRelease(msg);
            [message release];
        }

        CFRelease(sock);
    }
}

Как видно из комментария, в SendSsdpResponse я получаю сообщение об ошибке «EXC_BAD_ACCESS» при попыткевызвать CFSendSocketData.У меня есть подозрение, что это потому, что я «прохожу» sock, addr и msg, и есть что-то, что среда выполнения не любит в этом.Ранее я сталкивался с этой проблемой, передавая переменные типов данных CF другим функциям.Я еще не нашел ответа и надеюсь, что кто-то здесь, наконец, сможет помочь мне понять, что происходит за кулисами.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 01 декабря 2011

EXC_BAD_ACCESS ошибки обычно указывают, что вы пытаетесь вызвать метод в экземпляре, который уже был освобожден.Это часто имеет место, когда вам не удается правильно retain переменные, особенно когда они передаются между функциями.

Когда вы выполняете селектор с задержкой, в этой строке:

[self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

Вы предоставляете метод с переменной parameters, которая имеет свойства, определенные в указанном вами заголовке.Проблема в том, что сразу после метода performSelector: вы освобождаете память, относящуюся к addr и msg.Поскольку вы выполняете этот селектор с задержкой, память, на которую указывают addr и msg, освобождается до его использования .

Итак, когда эта память освобождена, онабольше не "хорошо" в объекте SsdpParameters.Вам следует (в установщике этих свойств на объекте SsdpParameters) скопировать эту память, чтобы исходные вызывающие абоненты могли безопасно ее освободить.

Вам следует изучить эту функцию:

CFDataRef CFDataCreateCopy (
   CFAllocatorRef allocator,
   CFDataRef theData
);

Тогда ваш сеттер может выглядеть так:

@implementation SsdpParameters

...

- (void)setMsg:(CFDataRef)m {
    // You should also release msg if it already exists
    msg = CFDataCreateCopy(CFAllocatorGetDefault(), m);
}

...

@end
0 голосов
/ 01 декабря 2011

Для устранения неполадок попробуйте заменить вызов на

[self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

с немедленным звонком на

[self SendSsdpResponse:parameters];

и посмотри, что получится.

Если вы все еще получаете «EXC_BAD_ACCESS», это означает, что ваши параметры каким-то образом установлены неправильно. Если, с другой стороны, вы не получаете сообщение об ошибке, это означает, что объект параметра изначально исправен, но становится недействительным до завершения задержки. Например, объект параметров сохраняет или копирует "addr" и "msg"?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...