按照网上找到的例子,尝试做简单的TCP发送和接收。
结果发现事实并不是那么回事,为什么?到stack overflow里看到一个原因说有可能delegate被系统自动释放掉,这样就不会有delegate。但是没有看到好的例子。
一般的例子就是在view controller里面引入GCDAsyncSocket.h然后开始初始化,然后就在view controller里面实现GCDAsyncSocketDelegate,然后就可以在view did load里面做初始化和调用连接,读取和写入这些。然后如果完成到相应的步骤,会有相应的delegate被呼叫。
不过,其实这样是不行的,只能写出去,但读取的delegate不会被执行。原因可能是view controller这个类本身在做完view did load之后就被系统自动释放了,然后socket的didReadData就为空,就不会被调用。
具体是不是这个原因我也不是很清楚,就是跟iOS系统的ARC机制有关,也跟GCD有关。这些概念我其实还不是很清楚。
总之我知道这是跟内存管理和进程调度有关。
如果不使用GCDAsyncSocket而采用旧的AsyncSocket则没有这种问题,能正常调用读写的delegate。所以感觉还简单一点。搞不懂为什么非要用GCD这种看起来高级,实际上很坑爹的方式。
不过我还是找到办法既可以用GCD,又可以让read的delegate执行的方法。稍微麻烦一点,就是自己定义一个class,在这个class里定义socket和实现相关的delegate,要注意的是这个class要提供一个share方法,里面会定义一个static的这个对象本身,这样就保证以后都一直能引用得到,而不会被系统自动释放掉。
+(TcpManager *)Share
{
static TcpManager *manager=nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
manager=[[TcpManager alloc]init];
manager.asyncsocket=[[GCDAsyncSocket alloc]initWithDelegate:manager delegateQueue:dispatch_get_main_queue()];
});
return manager;
}
这样在view controller里需要用tcp时
TcpManager *tcp = [TcpManager Share];
GCDAsyncSocket *socket = tcp.asyncsocket;
if (![socket connectToHost:@"192.168.1.212" onPort:5000 error:&err]) {
NSLog(@"fail to connect");
}
[socket readDataWithTimeout:3 tag:1];
[socket writeData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
用这种方式来调用就可以了。
完整的代码:
#import "ViewController.h"
#import "TcpManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
NSError *err = nil;
[super viewDidLoad];
NSLog(@"we are going to test tcp");
TcpManager *tcp = [TcpManager Share];
GCDAsyncSocket *socket = tcp.asyncsocket;
if (![socket connectToHost:@"192.168.1.212" onPort:5000 error:&err]) {
NSLog(@"fail to connect");
}
[socket readDataWithTimeout:3 tag:1];
[socket writeData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
}
@end
#import "TcpManager.h"
@interface TcpManager() <GCDAsyncSocketDelegate>
@end
@implementation TcpManager
+(TcpManager *)Share
{
static TcpManager *manager=nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
manager=[[TcpManager alloc]init];
manager.asyncsocket=[[GCDAsyncSocket alloc]initWithDelegate:manager delegateQueue:dispatch_get_main_queue()];
});
return manager;
}
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(@"didConnectToHost %@ port %d",host,port);
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
NSLog(@"disconnected");
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSLog(@"didReadData read data");
NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"message is: \n%@",message);
// [sock disconnect];
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// [sock disconnect];
NSLog(@"didWriteDataWithTag");
}
-(NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length
{
NSLog(@"timeout");
return 0;
}
-(BOOL)destroy
{
[_asyncsocket disconnect];
return YES;
}
@end
头文件:
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
//#import "AsyncSocket.h"
@interface TcpManager : NSObject
@property(strong,nonatomic) GCDAsyncSocket *asyncsocket;
+(TcpManager *)Share;
-(BOOL)destroy;
@end
其它的就不贴了。