我正在使用TCP短连接将数据发送到主机。当我想向主机发送数据时,我将实例化一个套接字,将套接字实例存储到一个数组中,然后在成功写入数据时将其删除。
我就这样做了:
- (void)connectAndSendData:(NSData *)data
{
GCDAsyncSocket *asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
[_connectionDataToBeSentMap setObject:data forKey:[NSValue valueWithNonretainedObject:asyncSocket]];
NSError *error;
if(![asyncSocket connectToHost:_host onPort:TCP_COMMUNICATION_PORT withTimeout:TCP_CONNECTION_TIMEOUT error:&error])
{
NSLog(@"TCPShortConnection - failed when attempting to connect to host with IP %@", _host);
}
[_connectionList addObject:asyncSocket];
}
写完数据后我会立即断开套接字。因此,之后将删除连接:
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
[_connectionList removeObject:sock];
if(err.code == GCDAsyncSocketConnectTimeoutError)
{
// NSLog(@"TCPShortConnection - on connection timed out");
[_delegate onTCPShortConnectionTimedOut];
}
else
{
// NSLog(@"TCPShortConnection - on disconnection of socket with host %@", _host);
}
}
此行[_connectionList removeObject:sock];
正在抛出NSRangeException。而且我不知道为什么。因为我通过删除空数组中的非现有对象进行了测试,所以不会抛出此类异常。
这是日志:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(0x258d9b0b 0x25096dff 0x257ea6d3 0x257ff033 0xfae43 0x1ca94d 0x4ccba7 0x4d8eff 0x4d87f1 0x2560ae0d 0x2560a9fc)
libc++abi.dylib: terminating with uncaught exception of type NSException
截图:
编辑:
请注意,这不是百分之百。
答案 0 :(得分:3)
猜猜:您正在从不同的线程访问NSMutableArray
说明:
NSMutableArray
不是线程安全的,并发读写也不安全 - 如果从GCD并发队列访问阵列时可能会发生这种情况。
GCDAsyncSocket
顾名思义就是使用GCD。特别是委托调用是在用户设置的GCD队列上调度的,并且该队列可以是并发的。
您正在将其中一个全局并发队列设置为委托队列。
解决方案:您应首先确定是否应该使用数组,我们无法为您确定。如果你需要数组,那么它需要是线程安全的。一个简单的方法是:
创建阵列时,还要为此阵列创建顺序 GCD队列。
要执行从阵列读取的数组方法,请在阵列的顺序队列上执行同步分派。您可以使用__block
变量从调度块返回结果。
要对阵列执行写操作,请使用异步分派到阵列的队列。
这个简单的模型确保数组上不能同时进行两个操作,并且所有读写都按照它们的调度顺序进行。
正如我在开始时所说,我猜测并发访问阵列是你的问题,你需要自己确定。如果是这样就应该解决它。
HTH
答案 1 :(得分:0)
这里有两个:
案例1: 在_connectionList数组中成功添加对象时。
[_connectionList addObject:asyncSocket];
在这种情况下,不会发生此类异常。
[_connectionList removeObject:sock];
成功从_connectionList数组中删除对象。
<强> CASE2:强> 当对象未在_connectionList数组中成功添加时。
在这里抛出一个例外,
[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]
因为该对象未在_connectionList数组中成功添加。
所以这个问题叫做读写器问题。
因为NSMutableArray不是线程安全的。