干貨:自定義Socket類
Socket.h
@protocol SocketDelegate <NSObject>//代理方法傳值出去
- (void)didReadData:(NSData *)data;
@end
@interface Socket : NSObject
- (void)socketConHost:(NSData *)message; //socket連接
- (void)sendMessage:(NSData *)message;//發(fā)送消息
@property(nonatomic,assign) id<SocketDelegate>dataDelegate;//代理
@end
Socket.m
@interface Socket()<NSStreamDelegate>{//遵守stream協(xié)議
// 輸入流,用來讀取服務(wù)器返回的字節(jié)
NSInputStream *_inputStream;
// 輸出流,用于給服務(wù)器發(fā)送字節(jié)
NSOutputStream *_outputStream;
}
@end
@implementation Socket
- (void)socketConHost:(NSData *)message{
// 創(chuàng)建CF下的讀入流
CFReadStreamRef readStream;
// 創(chuàng)建CF下的寫出流
CFWriteStreamRef writeStream;
NSString *host = @"XXX.XXX.XXX.XXX";
int port = XXXX;
// 創(chuàng)建流
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(host), port, &readStream, &writeStream);
// 將CFXXX流和NSXXX流建立對(duì)應(yīng)關(guān)系
_inputStream = (__bridge NSInputStream *)(readStream);
_outputStream = (__bridge NSOutputStream *)(writeStream);
// 設(shè)置通信過程中的代理
_inputStream.delegate = self;
_outputStream.delegate = self;
// 將流對(duì)象添加到主運(yùn)行循環(huán)(如果不加到主循環(huán),Socket流是不會(huì)工作的)
[_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(@"有可讀字節(jié)");
[self readData];
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可以寫入數(shù)據(jù)");
break;
case NSStreamEventErrorOccurred:
NSLog(@"發(fā)生錯(cuò)誤");
break;
case NSStreamEventEndEncountered:
NSLog(@"流結(jié)束");
// 做善后工作
// 關(guān)閉流的同時(shí),將流從主運(yùn)行循環(huán)中刪除
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[aStream setDelegate:nil];
break;
default:
break;
}
}
#pragma mark 傳入要發(fā)送的數(shù)據(jù)
- (void)sendMessage:(NSData *)message
{
[_outputStream write:message.bytes maxLength:message.length];
}
#pragma mark 讀了服務(wù)器返回的數(shù)據(jù)
-(void)readData{
//建立一個(gè)緩沖區(qū) 可以放1024個(gè)字節(jié)
uint8_t buf[1024];
// 返回實(shí)際裝的字節(jié)數(shù)
NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
// 把字節(jié)數(shù)組轉(zhuǎn)化成字符串
NSData *data = [NSData dataWithBytes:buf length:len];
// 從服務(wù)器接收到的數(shù)據(jù)
@try {
if ([_dataDelegate respondsToSelector:@selector(didReadData:)]) {
[_dataDelegate didReadData:data];//代理方法把數(shù)據(jù)傳出
}
}
@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;
}
//注意!!奢人!調(diào)用父類方法要放在最后,否則程序會(huì)報(bào)錯(cuò)淆院,具體原因似乎是蘋果的機(jī)制:先干掉大頭何乎,再干掉小的(所以是mrc)
[super dealloc];
}
至此封裝結(jié)束,外部調(diào)用實(shí)現(xiàn)代理方法即可獲取到值土辩。測(cè)試拿到數(shù)據(jù)后返回外部接收在1ms左右支救,效率可放心。