當AsyncSocket無法二次封裝---蘋果原生Stream流的救贖
乾貨:自定義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左右,效率可放心。
有任何問題歡迎留言,大家互相探討。
相關文章
- 天辰的救贖(JS)第一章(救贖之地)JS
- Dapper的封裝、二次封裝、官方擴充套件包封裝,以及ADO.NET原生封裝APP封裝套件
- css菜雞的自我救贖CSS
- 二次封裝 query ajax 辦法封裝
- 程式碼故事:漢德的救贖
- 聯想開啟物聯網救贖
- Oracle-AUL:黑夜前的最後救贖Oracle
- axios的二次封裝iOS封裝
- 《推理學院》玩家創作故事:救贖
- Android呼叫系統分享的坑與救贖Android
- 以虛擬化的名義救贖IT管理薦
- ajax原生js封裝JS封裝
- 原生js封裝AjaxJS封裝
- 【職場往事】卷不動的當下,功能測試該何去何從??完成自我的救贖
- Flutter Dio二次封裝Flutter封裝
- axios二次封裝iOS封裝
- 二次封裝WebDriverWait封裝WebAI
- 後疫情時代,酒店行業的掙扎與救贖!行業
- 原生Ajax封裝隨筆封裝
- elment dialog二次封裝封裝
- OpenResty Redis操作二次封裝RESTRedis封裝
- FMDB 二次封裝,面向模型封裝模型
- Stream流
- 天辰的救贖(JS)第三章(胖虎的指引)JS
- 節流防抖封裝封裝
- 原生es5封裝的Promise物件封裝Promise物件
- selenium-webdriver的二次封裝(十)Web封裝
- notification 全解和 api 的二次封裝API封裝
- 原生JS封裝AJAX請求JS封裝
- axios二次封裝學習iOS封裝
- uview-ui toast 二次封裝ViewUIAST封裝
- 天辰的救贖(JS)第四章(組合元素)JS
- 疫情之下,民宿行業的生死掙扎與自我救贖行業
- 一位拖延症患者程式設計師的自我救贖!程式設計師
- 智慧電視“套娃式”收費背後的自我救贖
- C++的救贖 C++開源程式庫評話(轉)C++
- 自我救贖 → 利用 IDEA 和 Spring Boot 搭建 SSMIdeaSpring BootSSM
- Stream 流模組