GCDAsyncSocket通信

//
//  ViewController.m
//  Socket1
//
//  Created by 阿仁欧巴 on 16/5/7.
//  Copyright © 2016年 aren. All rights reserved.
//

#import "ViewController.h"
#import "GCDAsyncSocket.h"

@interface ViewController () < UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate, GCDAsyncSocketDelegate>
{
    GCDAsyncSocket *_socket; //成员变量
}
//@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomViewConstraint;
@property (weak, nonatomic) IBOutlet UIView *commentView;//底部的文本框父视图,通过键盘的出现与否改变它的frame
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *chatMsgs; //聊天消息数组

@end

@implementation ViewController

- (NSMutableArray *)chatMsgs
{
    if (!_chatMsgs) {
        _chatMsgs = [NSMutableArray array];
    }
    return _chatMsgs;
}

//连接服务器的按钮
- (IBAction)connect:(id)sender
{
    //和服务器建立连接的步骤
    NSString *host = @"127.0.0.1";
    int port = 8080;
    //创建一个socket对象  代理方法都会在子线程调用,在刷新UI时就要回到主线程
    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    //链接服务器
    NSError *error = nil;
    
#pragma mark ---使用GCDAsyncSocket就不用将C语言形式的输入输出流转换成OC对象了,因为已经帮我们封装好了---
    
    [_socket connectToHost:host onPort:port error:&error];
    if (error) {
        NSLog(@"%@",error);
    }
    
}

//登录按钮
- (IBAction)login:(id)sender {
    
    //登录的指令
    NSString *logStr = @"iam:阿仁";
    NSData *data = [logStr dataUsingEncoding:NSUTF8StringEncoding];
    //发送登录消息数据给服务器 登录的时候
    [_socket writeData:data withTimeout:-1 tag:101];
    
}

#pragma mark --当数据成功发送到服务器, 才会执行下面的代理方法---

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    NSLog(@"数据成功发送到服务器");
    //,自己调用一下读取数据的方法, 发送数据成功后,接着_socket才会执行下面的方法,
    [_socket readDataWithTimeout:-1 tag:tag];
}

#pragma mark ---GCDAsyncSocketDelegate---

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    NSLog(@"链接主机成功");
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    if (err) {
        NSLog(@"和主机断开链接");
    }
}

#pragma mark ---服务器有数据, 就会执行这个方法---
//接收到数据
//点击键盘发送按钮,发送消息数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    //将接收到的数据转换成字符串形式,在tableView中展示出来
    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",dataString);
    //刷新表格
    if (tag == 102) {
        [self reloadDataWithText:dataString];
        NSLog(@"发送的是键盘输入的消息数据");
    } else if (tag == 101) {
        NSLog(@"发送的是登录数据");
    }
    
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    NSLog(@"%@",textField.text);
    NSString *msStr = textField.text;
    NSData *data = [msStr dataUsingEncoding:NSUTF8StringEncoding];
    //刷新表格 并且让表格自动滚动到最后一行的位置
    [self reloadDataWithText:textField.text];
    //_socket发送数据
    [_socket writeData:data withTimeout:-1 tag:102];
    //发送完成清空输入框
    textField.text = nil;
    
    return YES;
}

- (void)reloadDataWithText:(NSString *)text
{
    //将发送的消息存入本地数组中,作为数据源 展示在tableView上
    
    [self.chatMsgs addObject:text];
    
#pragma mark ---回到主线程刷新UI,因为在刚开始创建Socket设置代理的时候代理队列是全局并发队列,在子线程中执行---

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tableView reloadData];
    });
    
    //获取最后一行的indexPath
    NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.chatMsgs.count - 1 inSection:0];
    //tableView 自动滚动到最后一行
    [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    
}

#pragma mark --- 将要拖动时,键盘消失---
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //监听键盘将要出现时
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChang:) name:UIKeyboardWillChangeFrameNotification object:nil];
    //监听键盘将要隐藏时
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHidden:) name:UIKeyboardWillHideNotification object:nil];
    
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view insertSubview:_tableView atIndex:0];
    
    
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)keyboardWillChang:(NSNotification *)noti
{
    NSLog(@"%@",noti.userInfo);
    //键盘结束的y值
    CGRect kbEndFrame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    [UIView animateWithDuration:[noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{
        self.commentView.transform = CGAffineTransformMakeTranslation(0, -kbEndFrame.size.height);
    }];

}

- (void)keyboardWillHidden:(NSNotification *)noti
{
    //键盘结束的y值
    [UIView animateWithDuration:[noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{
        //让文本框视图变回初始的状态
        self.commentView.transform = CGAffineTransformIdentity;
    }];

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.chatMsgs.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    cell.textLabel.text = self.chatMsgs[indexPath.row];
    return cell;
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
原文地址:https://www.cnblogs.com/arenouba/p/5469665.html