关于即时聊天

https://github.com/coderMyy/MYCoreTextLabel 图文混排 , 实现图片文字混排 , 可显示常规连接好比网址,@,话题等 , 能够自定义连接字,设置关键字高亮等功能 . 适用于微博,微信,IM聊天对话等场景 . 实现这些功能仅用了几百行代码,耦合性也较低java

https://github.com/coderMyy/MYDropMenu 上拉下拉菜单,可随意自定义,随意修改大小,位置,各个项目通用git

https://github.com/coderMyy/MYPhotoBrowser 照片浏览器。功能主要有 : 点击点放大缩小 , 长按保存发送给好友操做 , 带文本描述照片,从点击照片放大,当前浏览照片缩小等功能。功能逐渐完善增长中.github

https://github.com/coderMyy/MYNavigationController 导航控制器的压缩 , 使得能够将导航范围缩小到指定区域 , 实现页面中的页面效果 . 适用于路径选择,文件选择等web

#pragma mark - ---------大致思路罗列 /*数据库

如下思路 , 仅表我的意见 , 且是我能想到比较好的处理方法

                    =====================================================================================
                                                                            <<< 大体代码结构 >>>

                                                                                GCDSocket
                                                                (提供最原始的写入,读取,超时等方法)
                                                                   delegate : ChatHandler单例
                                                                 怎么去发送消息,接收消息的实际操做者

                                                                                     ||
                                                                                    ⏬
                                                                                ChatHanlder
                        (做为中间业务逻辑处理层 , 主要将发送消息,接收消息和各个实际接收的控制器们链接起来,数据缓存,处理等)
                                delegate : 须要接收消息的全部对象 (注册成为ChatHandler的代理,ChatHandler中数组对各个对象进行存储)
                                    数据处理(数据库以及沙盒),数据缓存(数据库以及沙盒),消息发送接收业务逻辑处理实际操做者

                                            ||                                          ||                                   ||
                                           ⏬                                        ⏬                                 ⏬
                                   ViewController1                     ViewController2                    .........
                                                        
                 控制器里须要作的 , 是对内存中消息模型进行操做 , 以此更新UI . 好比进度显示 , 失败红叹号显示 , 转圈 , 消息删除 , 撤回等 ...


                                                                             这么设计的好处 :
                    1. 分工明确 , 每一个控制器获得的消息 , 都是能够直接使用的 , 控制器只须要负责主要和V层进行交互 , 避免了在控制器中处理过多的逻辑
                    2. ChatHandler做为全局单例 , 生命周期和整个应用保持一致 . 而控制器 , 会随着用户操做而销毁 , 若是把数据放到控制器里处理 , 极可能会形成数据的丢失

                        =====================================================================================
                                                                                <<< 关于缓存结构 >>>
                                                                        
                                文本/表情消息             语音消息            图片消息            视频消息            文件消息        撤回消息        提示语消息

                                        ||                             ||                      ||                       ||                      ||                    ||                    ||
                                       ⏬                           ⏬                    ⏬                     ⏬                   ⏬                  ⏬                  ⏬
                                 数据库存储               数据库存储          数据库存储         数据库存储        数据库存储       数据库存储      数据库存储
                                                                      ||                       ||                       ||
                                                        沙盒缓存(语音data)  沙盒缓存(图片data) 沙盒缓存(视频)


                        ===================================================================================
复制代码

<<<<Socket链接>>>>json

登陆 -> 链接服务器端口 -> 成功链接 -> SSL验证 -> 发送登陆TCP请求(login) -> 收到服务端返回登陆成功回执(loginReceipt) ->发送心跳 -> 出现链接中断 ->断网重连3次 -> 退出程序主动断开链接数组

<<<<关于链接状态监听>>>>浏览器

  1. 普通网络监听

因为即时通信对于网络状态的判断须要较为精确 ,原生的Reachability实际上在不少时候判断并不可靠 。 主要体如今当网络较差时,程序可能会出现链接上网络 , 但并未实际上可以进行数据传输 。 开始尝试着用Reachability加上一个普通的网络请求来双重判断实现更加精确的网络监听 , 可是其实是不可行的 。 若是使用异步请求依然判断不精确 , 如果同步请求 , 对性能的消耗会很大 。 最终采起的解决办法 , 使用RealReachability ,对网络监听同时 ,PING服务器地址或者百度 ,网络监听问题基本上得以解决缓存

  1. TCP链接状态监听:

TCP的链接状态监听主要使用服务器和客户端互相发送心跳 ,彼此验证对方的链接状态 。 规则能够本身定义 , 当前使用的规则是 ,当客户端链接上服务器端口后 ,且成功创建SSL验证后 ,向服务器发送一个登录的消息(login)。 当收到服务器的登录成功回执(loginReceipt)开启心跳定时器 ,每一秒钟向服务器发送一次心跳 ,心跳的内容以安卓端/iOS端/服务端最终协商后为准 。 当服务端收到客户端心跳时,也给服务端发送一次心跳 。正常接收到对方的心跳时,当前链接状态为已链接状态 ,当服务端或者客户端超过3次(自定义)没有收到对方的心跳时,判断链接状态为未链接。服务器

<<<<关于本地缓存>>>>

  1. 数据库缓存

建议每一个登录用户建立一个DB ,切换用户时切换DB便可 。 搭建一个完善IM体系 , 每一个DB至少对应3张表 。 一张用户存储聊天列表信息,这里假如它叫chatlist ,即微信首页 ,用户存储每一个群或者单人会话的最后一条信息 。来消息时更新该表,并更新内存数据源中列表信息。或者每次来消息时更新内存数据源中列表信息 ,退出程序或者退出聊天列表页时进行数据库更新。后者避免了频繁操做数据库,效率更高。 一张用户存储每一个会话中的详细聊天记录 ,这里假如它叫chatinfo。该表也是如此 ,要么接到消息立马更新数据库,要么先存入内存中,退出程序时进行数据库缓存。 一张用于存储好友或者群列表信息 ,这里假如它叫myFriends ,每次登录或者退出,或者修改好友备注,删除好友,设置星标好友等操做都须要更新该表。

  1. 沙盒缓存

当发送或者接收图片、语音、文件信息时,须要对信息内容进行沙盒缓存。 沙盒缓存的目录分层 ,我的建议是在每一个用户根据本身的userID在Cache中建立文件夹,该文件夹目录下建立每一个会话的文件夹。 这样作的好处在于 , 当你须要删除聊天列表会话或者清空聊天记录 ,或者app进行内存清理时 ,便于找到该会话的全部缓存。大体的目录结构以下 ../Cache/userID(当前用户ID)/toUserID(某个群或者单聊对象)/...(图片,语音等缓存)

<<<<关于消息分发>>>>

全局我们设定了一个ChatHandler单例,用于处理TCP的相关逻辑 。那么当TCP推送过来消息时,我该将这些消息发给谁?谁注册成为个人代理,我就发给谁。 ChatHandler单例为全局的,而且生命周期为整个app运行期间不会销毁。在ChatHandler中引用一个数组 ,该数组中存放全部注册成为须要收取消息的代理,当每来一条消息时,遍历该数组,并向全部的代理推送该条消息.

<<<<聊天UI的搭建>>>>

  1. 聊天列表UI(微信首页)

这个页面没有太多可说的 , 一个tableView便可搞定 。须要注意的是 ,每次收到消息时,都须要将该消息置顶 。每次进入程序时,拉取chatlist表存储的每一个会话的最后一条聊天记录进行展现 。

  1. 会话页面

该页面tableView或者collectionView都可实现 ,看我的喜爱 。这里是我用的是tableView . 根据消息类型大体分为普通消息 ,语音消息 ,图片消息 ,文件消息 ,视频消息 ,提示语消息(以上为打招呼内容,xxx已加入群,xxx撤回了一条消息等)这几种 ,固cell的注册差很少为5种类型,每种消息对应一种消息。 视频消息和图片消息cell能够复用 。 不建议使用过少的cell类型 ,首先是逻辑太多 ,不便于处理 。其次是效率并不高。

<<<<发送消息>>>>

  1. 文本消息/表情消息

直接调用我们封装好的ChatHandler的sendMessage方法便可 , 发送消息时 ,须要存入或者更新chatlist和chatinfo两张表。如果未链接或者发送超时 ,须要从新更新数据库存储的发送成功与否状态 ,同时更新内存数据源 ,刷新该条消息展现便可。 如果表情消息 ,传输过程也是以文本的方式传输 ,好比一个大笑的表情 ,能够定义为[大笑] ,固然规则本身能够和安卓端web端协商,本地根据plist文件和表情包匹配进行图文混排展现便可 。 https://github.com/coderMyy/MYCoreTextLabel ,图文混排地址 , 若是以为有用 , 请star一下 ,好人一辈子平安

  1. 语音消息

语音消息须要注意的是 ,多和安卓端或者web端沟通 ,找到一个你们均可以接受的格式 ,转码时使用同一种格式,避免某些格式其余端没法播放,我的建议Mp3格式便可。 同时,语音也须要作相应的降噪 ,压缩等操做。 发送语音大约有两种方式 。 一是先对该条语音进行本地缓存 , 而后所有内容均经过TCP传输并携带该条语音的相关信息,例如时长,大小等信息,具体的你得测试一条压缩后的语音体积有多大,如果过大,则须要进行分割而后以消息的方法时发送。接收语音时也进行拼接。同时发送或接收时,对chatinfo和chatlist表和内存数据源进行更新 ,超时或者失败再次更新。 二是先对该条语音进行本地缓存 , 语音内容使用http传输,传输到服务器生成相应的id ,获取该id再附带该条语音的相关信息 ,以TCP方式发送给对方,当对方收到该条消息时,先去下载该条信息,并根据该条语音的相关信息进行展现。同时发送或接收时,对chatinfo和chatlist表和内存数据源进行更新 ,超时或者失败再次更新。

  1. 图片消息

图片消息须要注意是 ,经过拍照或者相册中选择的图片应当分红两种大小 , 一种是压缩得很是小的状态,一种是图片自己的大小状态。 聊天页面展现的 ,仅仅是小图 ,只有点击查看时才去加载大图。这样作的目的在于提升发送和接收的效率。 一样发送图片也有两种方式 。 一是先对该图片进行本地缓存 , 而后所有内容均经过TCP传输 ,并携带该图片的相关信息 ,例如图片的大小 ,名字 ,宽高比等信息 。一样若是过大也须要进行分割传输。同时发送或接收时,对chatinfo和chatlist表和内存数据源进行更新 ,超时或者失败再次更新。 二是先对该图片进行本地缓存 , 而后经过http传输到服务器 ,成功后发送TCP消息 ,并携带相关消息 。接收方根据你该条图片信息进行UI布局。同时发送或接收时,对chatinfo和chatlist表和内存数据源进行更新 ,超时或者失败再次更新。

  1. 视频消息

视频消息值得注意的是 ,小的视频没有太多异议,跟图片消息的规则差很少 。只是当你从拍照或者相册中获取到视频时,第一时间要获取到视频第一帧用于展现 ,而后再发送视频的内容。大的视频 ,有个问题就是当你选择一个视频时,首先作的是缓存到本地,在那一瞬间 ,可能会出现内存峰值问题 。只要不是过大的视频 ,如今的手机硬件配置彻底能够接受的。而上传采起分段式读取,这个问题并不会影响太多。

视频消息我我的建议是走http上传比较好 ,由于内容通常偏大 。TCP部分仅须要传输该视频封面以及相关信息好比时长,下载地址等相关信息便可。接收方能够经过视频大小判断,若是是小视频能够接收到后默认自动下载,自动播放 ,大的视频则只展现封面,只有当用户手动点击时才去加载。具体的仍是须要根据项目自己的设计而定。

  1. 文件消息

文件方面 ,iOS端并不如安卓端那种可操做性强 ,安卓能够彻底获取到用户里的全部文件,iOS则有保护机制。一般iOS端发送的文件 ,基本上仅仅局限于当前app本身缓存的一些文件 ,原理跟发送图片相似。

  1. 撤回消息

撤回消息也是消息内容的一种类型 。例如 A给B发送了一条消息 "你好" ,服务端会对该条消息生成一个messageID ,接收方收到该条消息的messageID和发送方的该条消息messageID一致。若是发送端须要撤回该条消息 ,仅仅须要拿到该条消息messageID ,设置一下消息类型 ,发送给对方 ,当收到撤回消息的成功回执(repealReceipt)时,移除该会话的内存数据源和更新chatinfo和chatlist表 ,并加载提示类型的cell进行展现例如“你撤回了一条消息”便可。接收方收到撤回消息时 ,一样移除内存数据源 ,并对数据库进行更新 ,再加载提示类型的cell例如“张三撤回了一条消息”便可。

  1. 提示语消息

提示语消息一般来讲是服务器作的事情更多 ,除了撤回消息是须要客户端本身作的事情并很少。 当有人退出群 ,或者本身被群主踢掉 ,时服务端推送一条提示语消息类型,并附带内容,客户端仅仅须要作展现便可,例如“张三已经加入群聊”,“以上为打招呼内容”,“你已被踢出该群”等。 固然 ,撤回消息也能够这样实现 ,这样提示消息类型逻辑就至关统一,不会显得很乱 。把主要逻辑交于了服务端来实现。

<<<<消息删除>>>>

这里须要注意的一点是 ,相似微信的长按消息操做 ,我采用的是UIMenuController来作的 ,实际上有一点问题 ,就是第一响应者的问题 ,想要展现该menu ,必须将该条消息的cell置为第一响应者,而后底部的键盘失去第一响应者,会降下去 。因此该长按出现menu最好仍是自定义 ,根据计算相对frame进行布局较好,自定义程度也更好。

消息删除大概分为删除该条消息 ,删除该会话 ,清空聊天记录几种 删除该条消息仅仅须要移除本地数据源的消息模型 ,更新chatlist和chatinfo表便可。 删除该会话须要移除chatlist和chatinfo该会话对应的列 ,并根据当前登陆用户的userID和该会话的toUserID或者groupID移除沙盒中的缓存。 清空聊天记录,须要更新chatlist表最后一条消息内容 ,删除chatinfo表,并删除该会话的沙盒缓存.

<<<<消息拷贝>>>>

这个不用多说 ,一两句话搞定

<<<<消息转发>>>>

拿到该条消息的模型 ,并建立新的消息 ,把内容赋值到新消息 ,而后选择人或者群发送便可。

值得注意的是 ,若是是转发图片或者视频 ,本地沙盒中的缓存也应当copy一份到转发对象所对应的沙盒目录缓存中 ,不能和被转发消息的会话共用一张图或者视频 。由于好比 :A给B发了一张图 ,A把该图转发给了C ,A移除掉A和B的会话 ,那么若是是共用一张图的话 ,A和C的会话中就再也没法找到这张图进行展现了。

<<<<从新发送>>>>

这个没有什么好说的。

<<<<标记已读>>>>

功能实现比较简单 ,仅仅须要修改数据源和数据库的该条会话的未读数(unreadCount),刷新UI便可。

<<<<如下为大体的实现步骤>>>>

文本/表情消息 :

方式一: 输入 ->发送 -> 消息加入聊天数据源 -> 更新数据库 -> 展现到聊天会话中 -> 调用TCP发送到服务器(若超时,更新聊天数据源,更新数据库 ,刷新聊天UI) ->收到服务器成功回执(normalReceipt) ->修改数据源该条消息发送状态(isSend) -> 更新数据库 方式二: 输入 ->发送 -> 消息加入聊天数据源 -> 展现到聊天会话中 -> 调用TCP发送到服务器(若超时,更新聊天数据源,刷新聊天UI) ->收到服务器成功回执(normalReceipt) ->修改数据源该条消息发送状态(isSend) ->退出app或者页面时 ,更新数据库

语音消息 :(这里以http上传,TCP原理一致)

方式一: 长按录制 ->压缩转格式 -> 缓存到沙盒 -> 更新数据库->展现到聊天会话中,展现转圈发送中状态 -> 调用http分段式上传(若失败,刷新UI展现) ->调用TCP发送该语音消息相关信息(若超时,刷新聊天UI) ->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend) ->修改数据源该条消息发送状态(isSend)-> 更新数据库-> 刷新聊天会话中该条消息UI 方式二: 长按录制 ->压缩转格式 -> 缓存到沙盒 ->展现到聊天会话中,展现转圈发送中状态 -> 调用http分段式上传(若失败,更新聊天数据源,刷新UI展现) ->调用TCP发送该语音消息相关信息(若超时,更新聊天数据源,刷新聊天UI) ->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend -> 刷新聊天会话中该条消息UI - >退出程序或者页面时进行数据库更新

图片消息 :(两种考虑,一是展现和http上传均为同一张图 ,二是展现使用压缩更小的图,http上传使用选择的真实图片,想要作到精致,方法二更为可靠)

方式一: 打开相册选择图片 ->获取图片相关信息,大小,名称等,根据用户是否选择原图,考虑是否压缩 ->缓存到沙盒 -> 更新数据库 ->展现到聊天会话中,根据上传显示进度 ->http分段式上传(若失败,更新聊天数据,更新数据库,刷新聊天UI) ->调用TCP发送该图片消息相关信息(若超时,更新聊天数据源,更新数据库,刷新聊天UI)->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend) ->更新数据库 -> 刷新聊天会话中该条消息UI 方式二:打开相册选择图片 ->获取图片相关信息,大小,名称等,根据用户是否选择原图,考虑是否压缩 ->缓存到沙盒 ->展现到聊天会话中,根据上传显示进度 ->http分段式上传(若失败,更细聊天数据源 ,刷新聊天UI) ->调用TCP发送该图片消息相关信息(若超时,更新聊天数据源 ,刷新聊天UI)->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend) -> 刷新聊天会话中该条消息UI ->退出程序或者离开页面更新数据库

视频消息:

方式一:打开相册或者开启相机录制 -> 压缩转格式 ->获取视频相关信息,第一帧图片,时长,名称,大小等信息 ->缓存到沙盒 ->更新数据库 ->第一帧图展现到聊天会话中,根据上传显示进度 ->http分段式上传(若失败,更新聊天数据,更新数据库,刷新聊天UI) ->调用TCP发送该视频消息相关信息(若超时,更新聊天数据源,更新数据库,刷新聊天UI)->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend) ->更新数据库 -> 刷新聊天会话中该条消息UI 方式二:打开相册或者开启相机录制 ->压缩转格式 ->获取视频相关信息,第一帧图片,时长,名称,大小等信息 ->缓存到沙盒 ->第一帧图展现到聊天会话中,根据上传显示进度 ->http分段式上传(若失败,更细聊天数据源 ,刷新聊天UI) ->调用TCP发送该视频消息相关信息(若超时,更新聊天数据源 ,刷新聊天UI)->收到服务器成功回执 -> 修改数据源该条消息发送状态(isSend) -> 刷新聊天会话中该条消息UI ->退出程序或者离开页面更新数据库

文件消息: 跟上述一致 ,须要注意的是,若是要实现该功能 ,接收到的文件须要在沙盒中单独开辟缓存。好比接收到web端或者安卓端的文件

<<<<消息丢失问题>>>>

消息为何会丢失 ? 最主要缘由应该归结于服务器对客户端的网络判断不许确。尽管客户端已经和服务端创建了心跳验证 , 可是心跳始终是有间隔的,且TCP的链接中断也是有延迟的。例如,在此时我向服务器发送了一次心跳,而后网络失去了链接,或者网络信号很差。服务器接收到了该心跳 ,服务器认为客户端是处于链接状态的,向我推送了某我的向我发送的消息 ,然而此时我却不能收到消息,因此出现了消息丢失的状况。

补充: CocoaSyncSocket的三次握手四次挥手验证,仅仅表如今链接时确保可靠的链接和断开 ,而并不能保证消息数据传输中的可靠性 , 因此消息数据传输,咱们能够模拟三次握手进行传输.

解决办法 :客户端向服务端发送消息,服务端会给客户端返回一个回执,告知该条消息已经发送成功。因此,客户端有必要在收到消息时,也向服务端发送一个回执,告知服务端成功收到了该条消息。而客户端,默认收到的全部消息都是离线的,只有收到客户端的接收消息的成功回执后,才会移除掉该离线消息缓存,不然将会把该条消息以离线消息方式同步推送。离线消息后面会作解释。此时的双向回执,能够把消息丢失几率降到很是低 ,基本上算是模拟了一个消息数据传输的三次握手。

<<<<消息乱序问题>>>>

消息为何会乱序 ? 客户端发送消息,该消息会默认赋值当前时间戳 ,收到安卓端或者web端发来的消息时,该时间戳是安卓和web端获取,这样就可能会出现时间戳的偏差状况。好比当前聊天展现顺序并无什么问题,由于展现是收到一条展现一条。可是当退出页面从新进入时,若是拉取数据库是根据时间戳的降序拉取 ,那么就很容易出现混乱。 解决办法 :表结构设置自增ID ,消息的顺序展现以入库顺序为准 ,拉取数据库获取消息记录时,根据自增ID降序拉取 。这样就解决了乱序问题 ,至少保证了,展现的消息顺序和我聊天时的同样。尽管时间戳可能并不同是按照严谨的降序排列的。

<<<<离线消息>>>> 进入后台,接收消息提醒: 解决方式要么采用极光推送进行解决 ,要么让本身服务器接苹果的服务器也行。毕竟极光只是做为一个中间者,最终都是经过苹果服务器推送到每一个手机。

进入程序加载离线消息:此处须要注意的是,若服务器仅仅是把每条消息逐个推送过来,那么客户端会出现一些小问题,好比角标数为每次增长1,最后一条消息不断更新 ,直到离线消息接收到完毕,形成一种很差的体验。 解决办法:离线消息服务端所有进行拼接或者以jsonArray方式,并协议分割方式,客户端收到后仅需仅需切割,直接在角标上进行总数的相加,并直接更新最后一条消息便可。亦或者,设置包头信息,告知每条消息长度,切割方式等。

<<<<版本兼容性问题处理>>>> 其实 , 作IM遇到最麻烦的问题之一 , 就应当是版本兼容问题 . 即时通信的功能点有不少 , 项目不可能一期全部的功能所有作完 , 那么就会涉及到新老版本兼容的问题 . 固然若是服务端经验足够丰富 , 版本兼容的问题能够交于服务端来完成 , 客户端并不须要作太多额外的事情 . 若是是并行开发 , 服务端思路不够长远 ,或者产品需求变动频繁且比较大.那么客户端也须要作一些相应的版本兼容问题 . 处理版本兼容问题并不难 , 主要问题在于当增长一个新功能时 , 服务端或许会推送过来更多的字段 , 而老版本的项目数据库若是没有预留足够的字段 , 就涉及到了数据库升级 . 而当收到高版本新功能的消息时 , 客户端也应当对该消息作相应的处理 . 例如,老版本的app不支持消息撤回 , 而新版本支持消息撤回 , 当新版本发送消息撤回时 , 老版本能够拦截到这条未知的消息类型 , 作相应的处理 , 好比替换成一条提示"该版本暂不支持,请前往appstore下载新版本"等. 而当必要时 , 若是整个IM结构没有通过深思熟虑 , 还可能会涉及到强制升级 .

<<<<[有人@你]>>>> 对于 有人@你 这个功能的实现可分为2部分 :

  1. 聊天列表最后一条消息前展现[有人@你] ,例如 [有人@你]你好 . 由于有人@你这个功能只出如今群组中 ,因此在发送消息时 ,设立"toUser"字段便可,固然这个字段名能够本身设定,当发送端@多我的时,本身定义规则进行拼接(安卓端,iOS端,web端协商),例如@"userID1,userID2,userID3"则代表了我@了这三我的. 当接收端接收到toUser字段不为空时,切割遍历userID是否有本身的id便可.若是有,说明有人@我 ,偏好设置userdefault进行存储状态便可 .进入该条会话,清除userdefault .

  2. 聊天对话页的锚点展现 , 具体何时展现锚点,微信的逻辑大概是: 当一个群处于正常状态下,有人@我 ,右上角展现 "有人@我"按钮,点击按钮拉取全部的未读消息,这里是未读消息,而不是定位到"有人@我"那一条 . 若没有人@我,则展现"未读消息"按钮 , 定位也是到第一条未读消息位置

当一个群处于免打扰状态下,有人@我,右上角展现"有人@你"按钮 , 点击按钮 ,定位到 "有人@我"那一条.

这里个人作法是 , 直接拉取数据库从 "有人@你" 或者全部的未读消息到最新的一条消息间的全部消息, 这样作法对于用户量不是特别大的状况下 , 不会出现任何问题.如果消息数量特别庞大 , 几千甚至上万条 ,该作法就不适用了,拉取的数据过多,解决办法能够借鉴微信作法 , 定位时获取中间一段消息,而后进行上拉或者下拉再去相似分页的去拉取数据库.

<<<<[草稿]功能>>>> 草稿功能相对简单 ,跟 "有人@你" 展现逻辑差很少 , 当退出聊天会话页时,检查一下键盘输入框中是否有值 , 有值则userdefault存入该信息和对应的该条会话的userID或者groupID.聊天页面展现时,判断一下该条会话是否有草稿,若是有展现 . 进入聊天会话页时,也检查一次是否有草稿 ,若是有,自动弹起键盘,填充上次的内容便可.

<<<<注意事项>>>>

  1. 在搭建体系时 , 尽可能把数据和业务逻辑都抽取到ChatHandler中 , 控制器里只须要拿到直接可用的消息模型便可 . 否则后期功能增多 , 控制器里的逻辑和代码会愈来愈多 ,而且还须要考虑控制器的生命周期问题 , 比较麻烦

以上仅为大致的思路 , 实际上搭建IM , 更多的难点在于逻辑的处理和各类细节问题 . 好比数据库,本地缓存,和服务端的通讯协议,和安卓端私下通讯协议.以及聊天UI的细节处理,例如聊天背景实时拉高,图文混排等等一系列麻烦的事.没办法写到很详细 ,都须要本身仔细的去思考.难度并不算很大,只是比较费心.

写在最后 :

其实上述的思路什么的 , 也许看的时候并不以为复杂 , 可是实际上真正去搭建时 , 其中遇到的各类问题仍是很是的恶心 ,直到功能所有作完 ,才对总体有了一个比较全面的认识 . 还有就是不少人在求UI方面的代码 , 因为最近一直在抽时间学习java方面的东西 , UI的东西我会尽快的补上来 ,UI不难 ,难的是UI串起来的逻辑和细节 ...

https://github.com/coderMyy/CocoaAsyncSocket_Demo github地址 ,会持续更新关于即时通信的细节 , 以及最终的UI代码

相关文章
相关标签/搜索