Domanda

I'm having an issue that is more bemusing to me than anything. I'm trying to establish a socket connection in Objective-C using GCDAsyncSocket. My connectToHost message sent to my GCDAsyncSocket fails with an EXC_BAD_ACCESS if and only if the socket variable is called socket. It's not a problem, exactly, because it's easy for me to use a different variable name, but I'm curious as to why that would happen.

Here is what I believe is the relevant portion of my code, from a class I created called SocketManager. Most of the code is taken from the GCDAsyncSocket intro. The code below fails with EXC_BAD_ACCESS at the indicated line.

#import "SocketManager.h"
#import "GCDAsyncSocket.h"

@implementation SocketManager

GCDAsyncSocket *socket;

-(id) init {
    self = [super init];

    socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

    NSError *err = nil;

    // EXC_BAD_ACCESS happens at the line below
    if (![socket connectToHost:@"localhost" onPort:26400 error:&err]) NSLog(@"I goofed: %@", err);

    NSLog(@"just created socket");

    return self;
}

However, if I change the variable name from socket to sock or banana or any other name, the code runs fine, which kind of weirds me out. Why would that happen? Is socket some kind of reserved system word? If that's the case, I would expect the code to not compile at all, but I'm pretty new to Objective-C.

Incidentally, my didConnectToHost: delegate method is rarely ever called, which I think is a separate issue but for all I know, it could be related.

È stato utile?

Soluzione

As @bburn suggested, this is a symbol collision. There is a BSD socket() function which GCDAsyncSocket uses. If you look at the EXC_BAD_ACCESS in the debugger, you'll see that it's actually failing when attempting to call socket() because it's resolving the function address to that of your variable.

Aside from renaming the variable, you can do a couple of things (I think it would be a good idea to do one of these things even if you also rename the variable):

  1. Declare the variable to be static. This will confine the scope of your variable to that file so that it cannot be accidentally resolved by GCDAsyncSocket. It would be a good idea to remove it from the global namespace anyway.
  2. Make it a private member variable.

To change it to a private member variable, change this:

@implementation Socketmanager
GCDAsyncSocket *socket;

to this:

@interface SocketManager()
{    
    GCDAsyncSocket *socket;
}
@end

@implementation SocketManager
...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top