模擬群聊的簡(jiǎn)單實(shí)現(xiàn)

前言

  • 上一章我們主要講述了如何利用服務(wù)器實(shí)現(xiàn)群聊.本章主要學(xué)習(xí)是從客戶(hù)端的角度簡(jiǎn)單實(shí)現(xiàn)群聊功能.
步驟:
  • 1, 導(dǎo)入框架并且描述storyboard.設(shè)置"dataSource"監(jiān)聽(tīng)?zhēng)讉€(gè)控件等.見(jiàn)下圖 1.
Snip20160309_2.png
  • 2, 創(chuàng)建客戶(hù)端的Socket對(duì)象,連接QQ服務(wù)器
#import "ViewController.h"
#import "GCDAsyncSocket.h"


@interface ViewController ()<GCDAsyncSocketDelegate, UITableViewDataSource>

/** 消息編輯框 */
@property (weak, nonatomic) IBOutlet UITextField *textField;

/** 顯示聊天內(nèi)容的tableView */
@property (weak, nonatomic) IBOutlet UITableView *chatTableView;

/** 發(fā)送消息 */
- (IBAction)sendMessage:(UIButton *)sender;

/** 客戶(hù)端的Socket對(duì)象 */
@property(nonatomic, strong) GCDAsyncSocket *clientSocket;

/** 數(shù)據(jù)源 */
@property(nonatomic, strong) NSMutableArray *dataSources;

@end

@implementation ViewController

#pragma mark - 懶加載
- (NSMutableArray *)dataSources
{
    if (_dataSources == nil) {
        _dataSources = [NSMutableArray array];
    }
    return _dataSources;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 創(chuàng)建客戶(hù)端的Socket對(duì)象
    GCDAsyncSocket *clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    
    // 發(fā)送連接請(qǐng)求
    NSError *error = nil;
    [clientSocket connectToHost:@"192.168.1.100" onPort:1886 error:&error];
    
    // 判斷是否連接成功,但是真正的連接不是在這兒,而是在代理方法中連接或者斷開(kāi).
    if (!error) {
        NSLog(@"連接成功");
    } else
    {
        NSLog(@"連接失敗啦%@",error);
    }
    
    // 保存創(chuàng)建好的客戶(hù)端的Socket對(duì)象
    self.clientSocket = clientSocket;
}
  • 注意點(diǎn) :

    • 1, clientSocket是一個(gè)局部變量,所以需要定義一個(gè)屬性強(qiáng)引用,這樣在后面的的方法中才能拿到該對(duì)象.
  • 2, 定義一個(gè)可變的數(shù)組,用于保存客戶(hù)端發(fā)送的消息(客戶(hù)端每發(fā)送一次消息就需要將消息保存到數(shù)組中),而且這個(gè)可變數(shù)組需要懶加載,用到時(shí)再創(chuàng)建.

  • 3, 請(qǐng)求連接之后,真正的連接或者斷開(kāi)連接都是在代理方法中可以驗(yàn)證的.

#pragma mark - GCDAsyncSocketDelegate
/**
 *  只要客戶(hù)端和服務(wù)器連接成功就會(huì)調(diào)該方法,第一個(gè)參數(shù)是客戶(hù)端,clientSocket是一個(gè)局部變量,所以需要定義成
 *  一個(gè)屬性強(qiáng)引用著.
 */
- (void)socket:(GCDAsyncSocket *)clientSocket didConnectToHost:(NSString *)host port:(uint16_t)port
{
    NSLog(@"連接成功");
    // 連接成功,接收客戶(hù)端發(fā)送的數(shù)據(jù)
    [clientSocket readDataWithTimeout:-1 tag:0];

}

/**
 *  只要斷開(kāi)連接就一定會(huì)來(lái)到這個(gè)方法
 */
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    NSLog(@"斷開(kāi)連接");
}
  • 4, 客戶(hù)端接收消息
/**
 *  監(jiān)聽(tīng)客戶(hù)端是否發(fā)送了消息,只要發(fā)送了消息就會(huì)來(lái)到這個(gè)方法, 讀取信息
 */
- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag
{

    // 將發(fā)送的數(shù)據(jù)轉(zhuǎn)化為字符串
    NSString *messageStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    // 判斷客戶(hù)端是否發(fā)送了消息,如果發(fā)送了消息,將消息保存至數(shù)據(jù)源中
    if (messageStr) {
        
        // 保存消息
        [self.dataSources addObject:messageStr];
    }
    
    // 刷新UI,必須要回到主線程,否則數(shù)據(jù)顯示不出來(lái)
    [[NSOperationQueue mainQueue]addOperationWithBlock:^{
        // 刷新表格
        [self.chatTableView reloadData];
    }];
    
    // 讀取(接收)數(shù)據(jù)
    [clientSocket readDataWithTimeout:-1 tag:0];
}
  • 注意點(diǎn) :

    • 1, 將NSData轉(zhuǎn)為字符串后,需要判斷是否為空,如果不為空需要將字符串保存到dataSources數(shù)組中.
  • 2, 接收到數(shù)據(jù)之后需要展示數(shù)據(jù),所以需要刷新表格,但是,當(dāng)前線程是在全局線程上執(zhí)行的,也就是說(shuō)當(dāng)前是一個(gè)異步函數(shù),屬于子線程,所以需要回到主線程上執(zhí)行刷新操作.

  • 3, 當(dāng)刷新表格后都要監(jiān)聽(tīng)讀取數(shù)據(jù),否則顯示一次數(shù)據(jù)之后,就不會(huì)再接收任何數(shù)據(jù)了.

  • 4, 數(shù)據(jù)源方法,用于展示數(shù)據(jù)到tableView上

#pragma mark - UITableViewDataSource

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    // 定義一個(gè)標(biāo)識(shí)和Storyboard中定義的ID一致
    NSString * const ID = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    cell.textLabel.text = self.dataSources[indexPath.row];
    
    return cell;
}
  • 5, 監(jiān)聽(tīng)發(fā)送按鈕
- (IBAction)sendMessage:(UIButton *)sender {
    
    NSString *str = self.textField.text;
    
    if (str == 0) {   //  說(shuō)明沒(méi)有消息發(fā)送
        return;
    }
    
    // 來(lái)到這里表示有發(fā)送消息
    
    // 將消息保存到數(shù)據(jù)源中
    [self.dataSources addObject:str];
    
    // 刷新表格
    [self.chatTableView reloadData];
    
    // 發(fā)送消息
    [self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}
  • 注意 :

    • 1, 需要判斷消息編輯框中是否有數(shù)據(jù),如果沒(méi)有,直接返回,如果有,那么將數(shù)據(jù)保存到數(shù)組中, 刷新表格,最后發(fā)送消息.
  • 知識(shí)拓展

    • 1, 客戶(hù)端有沒(méi)有連接或者是有沒(méi)有斷開(kāi)都是是通過(guò)代理方法來(lái)檢驗(yàn)的.
    • 2, 全局隊(duì)列是異步函數(shù)的,執(zhí)行耗時(shí)操作是在子線程, 刷新表格需要回到主線程上去進(jìn)行刷新操作.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末歹河,一起剝皮案震驚了整個(gè)濱河市豪治,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖刀闷,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)菌羽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)由缆,“玉大人注祖,你說(shuō)我怎么就攤上這事【Γ” “怎么了是晨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浸卦。 經(jīng)常有香客問(wèn)我署鸡,道長(zhǎng)案糙,這世上最難降的妖魔是什么限嫌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮时捌,結(jié)果婚禮上怒医,老公的妹妹穿的比我還像新娘。我一直安慰自己奢讨,他們只是感情好稚叹,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拿诸,像睡著了一般扒袖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亩码,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天季率,我揣著相機(jī)與錄音,去河邊找鬼描沟。 笑死飒泻,一個(gè)胖子當(dāng)著我的面吹牛鞭光,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泞遗,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惰许,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了史辙?” 一聲冷哼從身側(cè)響起汹买,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎聊倔,沒(méi)想到半個(gè)月后卦睹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡方库,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年结序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纵潦。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡徐鹤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邀层,到底是詐尸還是另有隱情返敬,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布寥院,位于F島的核電站劲赠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏秸谢。R本人自食惡果不足惜凛澎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望估蹄。 院中可真熱鬧塑煎,春花似錦、人聲如沸臭蚁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)垮兑。三九已至冷尉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間系枪,已是汗流浹背雀哨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗤无,地道東北人震束。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓怜庸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親垢村。 傳聞我的和親對(duì)象是個(gè)殘疾皇子割疾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)嘉栓,斷路器宏榕,智...
    卡卡羅2017閱讀 134,715評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,322評(píng)論 25 707
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司侵佃,掛了不少麻昼,但最終還是拿到小米、百度馋辈、阿里抚芦、京東、新浪迈螟、CVTE叉抡、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,278評(píng)論 11 349
  • 記得讀高二的時(shí)候,教語(yǔ)文的馬老師在課堂上講了一句話:“夕陽(yáng)無(wú)限好答毫,只是近黃昏”褥民,接著他頓了頓,又一...
    夏麗婭閱讀 717評(píng)論 0 1
  • “核心素養(yǎng)體系的提出被認(rèn)為是課程改革深化階段的破題之作”洗搂,今天有幸聆聽(tīng)了黃翔教授對(duì)核心素養(yǎng)與課程改革的深化的解讀消返,...
    輕寒微暖閱讀 374評(píng)論 0 3