干货:自定义Socket类
Socket.h
@protocol SocketDelegate <NSObject>//代理方法传值出去
- (void)didReadData:(NSData *)data;
@end
@interface Socket : NSObject
- (void)socketConHost:(NSData *)message; //socket连接
- (void)sendMessage:(NSData *)message;//发送消息
@property(nonatomic,assign) id<SocketDelegate>dataDelegate;//代理
@end
Socket.m
@interface Socket()<NSStreamDelegate>{//遵守stream协议
// 输入流,用来读取服务器返回的字节
NSInputStream *_inputStream;
// 输出流,用于给服务器发送字节
NSOutputStream *_outputStream;
}
@end
@implementation Socket
- (void)socketConHost:(NSData *)message{
// 创建CF下的读入流
CFReadStreamRef readStream;
// 创建CF下的写出流
CFWriteStreamRef writeStream;
NSString *host = @"XXX.XXX.XXX.XXX";
int port = XXXX;
// 创建流
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(host), port, &readStream, &writeStream);
// 将CFXXX流和NSXXX流建立对应关系
_inputStream = (__bridge NSInputStream *)(readStream);
_outputStream = (__bridge NSOutputStream *)(writeStream);
// 设置通信过程中的代理
_inputStream.delegate = self;
_outputStream.delegate = self;
// 将流对象添加到主运行循环(如果不加到主循环,Socket流是不会工作的)
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 打开流
[_inputStream open];
[_outputStream open];
}
#pragma mark stream的代理方法
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
NSLog(@"%lu",eventCode);
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"连接完成");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"有可读字节");
[self readData];
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可以写入数据");
break;
case NSStreamEventErrorOccurred:
NSLog(@"发生错误");
break;
case NSStreamEventEndEncountered:
NSLog(@"流结束");
// 做善后工作
// 关闭流的同时,将流从主运行循环中删除
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[aStream setDelegate:nil];
break;
default:
break;
}
}
#pragma mark 传入要发送的数据
- (void)sendMessage:(NSData *)message
{
[_outputStream write:message.bytes maxLength:message.length];
}
#pragma mark 读了服务器返回的数据
-(void)readData{
//建立一个缓冲区 可以放1024个字节
uint8_t buf[1024];
// 返回实际装的字节数
NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
// 把字节数组转化成字符串
NSData *data = [NSData dataWithBytes:buf length:len];
// 从服务器接收到的数据
@try {
if ([_dataDelegate respondsToSelector:@selector(didReadData:)]) {
[_dataDelegate didReadData:data];//代理方法把数据传出
}
}
@catch (NSException *exception) {
}
@finally {
}
}
#pragma mark 释放
- (void)dealloc {
//释放输入输出流
if (_outputStream) {
[_outputStream close];
[_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
_outputStream = nil;
}
if (_inputStream) {
[_inputStream close];
[_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
_inputStream = nil;
}
//注意!!!调用父类方法要放在最后,否则程序会报错,具体原因似乎是苹果的机制:先干掉大头,再干掉小的(所以是mrc)
[super dealloc];
}
至此封装结束,外部调用实现代理方法即可获取到值。测试拿到数据后返回外部接收在1ms左右,效率可放心。