標籤:
GCDAsyncSocket編程
同上一篇文章一樣,這裡也是使用Socket實現一個聊天室,但是這裡使用的是一個常用的架構實現的:GCDAsyncSocket
一:匯入這個架構
二:聲明這個Socket的成員變數,定義一個訊息數組
1 @interface ViewController ()<UITextFieldDelegate,UITableViewDataSource,UITableViewDelegate,GCDAsyncSocketDelegate>{ 2 3 GCDAsyncSocket *_socket; 4 } 5 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *inputViewConstraint; 6 @property (weak, nonatomic) IBOutlet UITableView *tableView; 7 8 @property (nonatomic, strong) NSMutableArray *chatMsgs;//聊天訊息數組 9 10 @end
懶載入訊息數組
1 -(NSMutableArray *)chatMsgs{2 if (!_chatMsgs) {3 _chatMsgs = [NSMutableArray array];4 }5 6 return _chatMsgs;7 }
三:連結的伺服器
1 - (IBAction)connectToHost:(id)sender { 2 // 1.建立串連 3 NSString *host = @"127.0.0.1"; 4 int port = 12345; 5 6 // 建立一個Socket對象 7 _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 8 9 // 串連10 NSError *error = nil;11 [_socket connectToHost:host onPort:port error:&error];12 if (error) {13 NSLog(@"%@",error);14 }15 }
連結與中斷連線的代理方法
1 #pragma mark -AsyncSocket的代理 2 #pragma mark 串連主機成功 3 -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{ 4 NSLog(@"串連主機成功"); 5 } 6 7 #pragma mark 與主機中斷連線 8 -(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{ 9 10 if(err){11 NSLog(@"中斷連線 %@",err);12 }13 }
四:登陸
1 - (IBAction)loginBtnClick:(id)sender { 2 3 // 登入 4 // 發送使用者名稱和密碼 5 // 在這裡做的時候,只發使用者名稱,密碼就不用發送 6 7 // 如果要登入,發送的資料格式為 "iam:zhangsan"; 8 // 如果要發送聊天訊息,資料格式為 "msg:did you have dinner"; 9 10 //登入的指令11 NSString *loginStr = @"iam:zhangsan";12 13 //把Str轉成NSData14 NSData *data = [loginStr dataUsingEncoding:NSUTF8StringEncoding];15 16 17 //[_outputStream write:data.bytes maxLength:data.length];18 // 發送登入指令給服務19 [_socket writeData:data withTimeout:-1 tag:101];20 }
五:發送資料
1 -(BOOL)textFieldShouldReturn:(UITextField *)textField{ 2 3 NSString *text = textField.text; 4 5 NSLog(@"%@",text); 6 // 聊天資訊 7 NSString *msgStr = [NSString stringWithFormat:@"msg:%@",text]; 8 9 //把Str轉成NSData10 NSData *data = [msgStr dataUsingEncoding:NSUTF8StringEncoding];11 12 // 重新整理表格13 [self reloadDataWithText:msgStr];14 15 // 發送資料16 [_socket writeData:data withTimeout:-1 tag:102];17 18 // 發送完資料,清空textField19 textField.text = nil;20 21 return YES;22 }23 24 #pragma mark 資料成功發送到伺服器25 -(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{26 NSLog(@"資料成功發送到伺服器");27 //資料發送成功後,自己調用一下讀取資料的方法,接著_socket才會調用下面的代理方法28 [_socket readDataWithTimeout:-1 tag:tag];29 }30 31 #pragma mark 伺服器有資料,會調用這個方法32 -(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{33 // 從伺服器接收到的資料34 NSString *recStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];35 36 NSLog(@"%@ %ld %@",[NSThread currentThread],tag, recStr);37 38 if (tag == 102) {//聊天返回的資料39 // 重新整理表格40 [self reloadDataWithText:recStr];41 }42 // }else if(tag == 101 ){//登入返回資料,不應該把資料添加到表格裡43 //44 //45 // }46 47 }
六:載入聊天資料到介面,並且實現滾動到對應的位置,鍵盤的鍵盤
1 -(void)reloadDataWithText:(NSString *)text{ 2 [self.chatMsgs addObject:text]; 3 4 // UI重新整理要主線程 5 dispatch_async(dispatch_get_main_queue(), ^{ 6 [self.tableView reloadData]; 7 8 // 資料多,應該往上滾動 9 NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.chatMsgs.count - 1 inSection:0];10 [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];11 });12 13 }14 15 #pragma mark 表格的資料來源16 17 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{18 return self.chatMsgs.count;19 }20 21 22 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath23 {24 static NSString *ID = @"Cell";25 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];26 27 cell.textLabel.text = self.chatMsgs[indexPath.row];28 29 return cell;30 }31 32 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{33 [self.view endEditing:YES];34 }
鍵盤處理
1 2 // 監聽鍵盤 3 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbFrmWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil]; 4 } 5 6 7 -(void)kbFrmWillChange:(NSNotification *)noti{ 8 NSLog(@"%@",noti.userInfo); 9 10 // 擷取視窗的高度11 12 CGFloat windowH = [UIScreen mainScreen].bounds.size.height;13 14 15 16 // 鍵盤結束的Frm17 CGRect kbEndFrm = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];18 // 擷取鍵盤結束的y值19 CGFloat kbEndY = kbEndFrm.origin.y;20 21 22 self.inputViewConstraint.constant = windowH - kbEndY;23 }
iOS開發——網路編程OC篇&GCDAsyncSocket編程