2014年7月23日 星期三

iOS 開發筆記 - 使用 GCDAsyncSocket / AsyncSocket 之處理 Partial Data 的用法

原本想寫寫 BSD Socket 的,再搭配 dispatch_async 其實也能運作的很好,但讓我想起去年底面試一間新創時,被問到有沒有用過 GCDAsyncSocket 的心得,看來用用已經常見的 framework / library 已是一種流行的或組織文化吧?至少接手的人可以有一樣的思維而不用再去認識另一個 coding style 吧!

把玩 GCDAsyncSocket 時,一開始試用了 readDataToData 函數,但發現這東西不是我想要的,也就是 server 沒有吐出預設字元(newline)時,程式端無法處理已接收的資料,但可以得知已經接收多少 Partial Data (可用在回報下載、上傳進度)。爾後用一些關鍵字(partial data)找找,發現也有人有這種需求:Is there a way to get partial data read and clear the buffer?

原來會有這種困惑只是不懂 GCDAsyncSocket 設計架構,搞懂後就一切安好啦。

There are 3 methods of reading data using GCDAsyncSocket / AsyncSocket:
  • readDataWithTimeout : reads chunks of data as they arrive
  • readDataToLength : read a specific length of data before returning result
  • readDataToData : read until finding a specific terminator

對於不能確定 Server 回傳的資料長度或特徵的行為,就適合採用 readDataWithTimeout 方式 :)

- (GCDAsyncSocket*)asyncSocket {
if(!_asyncSocket)
_asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_queue_create("socket", NULL)];
return _asyncSocket;
}

- (NSMutableData *)buffer {
if (!_buffer) {
_buffer = [[NSMutableData alloc] init];
}
return _buffer;
}

- (void)viewDidLoad {
[super viewDidLoad];

if (![self.asyncSocket connectToHost:@"ServerIP" onPort:80 error:&error]) {
NSLog(@"ERROR: %@", error);
}
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(@"didConnectToHost");
[sock readDataWithTimeout:-1 buffer:self.buffer bufferOffset:[self.buffer length] tag:1];
}

- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
NSLog(@"didReadPartialDataOfLength");
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(@"didReadData(%lu): %@", tag, @([data length]));
[self.buffer setLength:0];
[sock readDataWithTimeout:-1 buffer:self.buffer bufferOffset:[self.buffer length] tag:tag];
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSLog(@"socketDidDisconnect: %@", err);
}

- (void)socketDidSecure:(GCDAsyncSocket *)sock {
NSLog(@"socketDidSecure");
}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(@"didWriteDataWithTag");
}

沒有留言:

張貼留言