2011-12-01 54 views
2

我使用这个类的一个实例来传递给函数所需的值发送套接字数据:EXC_BAD_ACCESS在调用CFSocketSendData

@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"); 
    } 
} 

此功能设置了插座和1秒的延迟后调用SendSsdpResponse:

- (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中,尝试调用CFSendSocketData时出现“EXC_BAD_ACCESS”错误。我有一个怀疑,这是因为我“通过”sock,addrmsg,有一些运行时不喜欢这个。我之前遇到过这个问题,将CF数据类型的变量传递给其他函数。我还没有找到答案,希望这里的某个人终于可以帮助我理解幕后发生的事情。

谢谢!

回答

2

EXC_BAD_ACCESS错误通常表明您正试图对已经释放的实例调用方法。当你无法正确地使用retain变量时,通常是这种情况,尤其是当它们在函数之间传递时。

当你在这条线与所述延迟执行选择器,:

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

你提供与parameters变量,其具有的属性,如你提供的报头中定义的方法。问题是,在performSelector:方法之后,您将释放内存,请参阅addrmsg。由于您正在执行此选择器的延迟,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 
+1

我一定是一直在寻找这个解决方案,就像你输入它一样。我愚蠢地认为应用程序会阻塞performSelector:withObject:afterDelay,并且CFRelease调用在执行完成之后才会运行。我仍然习惯于异步编程,这是另一个例子,说明如果理解不存在,人们可能会被它咬死。为了使它工作,我将CFRelease调用移动到了SendSsdpResponse,但我一定会考虑CFDataCreateCopy。 – Moebius

+0

啊,哈哈是的,它可能是一个非常棘手的问题。如果您打算使用异步代码,尤其是一次性的一次性任务,我强烈建议您查看Grand Central Dispatch。 –

+1

我刚刚在访问器上看到了您的新评论,以及您对发布“msg”的评论(如果它已存在)。我知道CFRelease会做释放,但我不确定如何检查存在。我正在使用'if(msg){CFRelease(msg); }'它似乎工作... – Moebius

0

要解决问题,尝试用立即更换呼叫

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

致电

[self SendSsdpResponse:parameters]; 

看看会发生什么。

如果您仍然收到“EXC_BAD_ACCESS”,这意味着您的参数设置不正确。另一方面,如果您没有收到错误,则表示参数对象最初是正常的,但在延迟完成之前变为无效。例如,参数对象是保留还是复制“addr”和“msg”?

+1

非常接近。提到参数你正走在正确的轨道上。感谢您的回应。 – Moebius