iOS开发之聊天模块--内容保存逻辑实现

需求详解:

在实际开发中,有可能是在后期优化的时候,会有这么需要优化的需求:聊天输入框保存之前输入的文本,提高用户的良好体验。

在聊天模块中,用户可能会在输入框输入若干字符,但是没有点击发送就点击退出聊天,或者要点击用户头像确认用户的信息,或者比如需要向好友发送另一个好 友的ID不得不暂时退出当前好友聊天界面跳转找到别的界面找ID,然而当前聊天输入框也已经输入好了若干字符,用户当然不希望退出之后就删除之前输入好的 文字。所以这里就需要暂时保存用户输入好的但是没有发送出去的字符串。

但是,还需要满足1、完全杀掉或者完全退出应用就需要清除这个暂时保存的字符串,2、发送出去之后,肯定就要delegate之前暂时保存的字符串喽。

开始:

这部分逻辑的实现一开始我没怎么比较好的头绪,只想到本地序列化,但实际上这个还不算是最好的思路,因为本地序列化用到这里有点小题大做了,其实只要用全局静态变量的字典就可以了。

具体实现的逻辑,我也特意阅读研究了Coding项目的实现,毕竟这个项目是比较成熟的项目,聊天模块也做的很不错,所以学学别人的思想,正所谓站在巨人的肩膀上,也是很好的哦。

那么下面,我就直接解读Coding源码(学习Coding-iOS开源项目日志(一))在这个聊天模块内容保存的逻辑吧,就不拿自己工作开发的项目来讲了。

1、首先声明全局static的变量,Coding中用inputStrDict存储输入框的字符串,而inputMediaDict我暂时不知道它具体存什么的,应该是media之类的元素:

2、然后将很多逻辑封装在这个UIMessageInputView类中,方法都不用公开,完全利用UIMessageInputView活动周期的逻辑就可以了。


  1. #pragma mark remember input 
  2.   
  3.  - (NSMutableDictionary *)shareInputStrDict{ 
  4.      if (!_inputStrDict) { 
  5.          _inputStrDict = [[NSMutableDictionary alloc] init]; 
  6.      } 
  7.      return _inputStrDict; 
  8.  } 
  9.   
  10. - (NSMutableDictionary *)shareInputMediaDict{ 
  11.     if (!_inputMediaDict) { 
  12.         _inputMediaDict = [[NSMutableDictionary alloc] init]; 
  13.     } 
  14.     return _inputMediaDict; 
  15.  
  16. - (NSString *)inputKey{ 
  17.     NSString *inputKey = nil; 
  18.     if (_contentType == UIMessageInputViewContentTypePriMsg) { 
  19.         inputKey = [NSString stringWithFormat:@"privateMessage_%@", self.toUser.global_key]; 
  20.     }else{ 
  21.         if (_commentOfId) { 
  22.             switch (_contentType) { 
  23.                 case UIMessageInputViewContentTypeTweet: 
  24.                     inputKey = [NSString stringWithFormat:@"tweet_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0? _toUser.global_key:@""]; 
  25.                     break; 
  26.                 case UIMessageInputViewContentTypeTopic: 
  27.                     inputKey = [NSString stringWithFormat:@"topic_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0? _toUser.global_key:@""]; 
  28.                     break; 
  29.                 case UIMessageInputViewContentTypeTask: 
  30.                     inputKey = [NSString stringWithFormat:@"task_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0? _toUser.global_key:@""]; 
  31.                     break; 
  32.                 default: 
  33.                     break; 
  34.             } 
  35.         } 
  36.     } 
  37.     return inputKey; 
  38.  
  39. - (NSString *)inputStr{ 
  40.     NSString *inputKey = [self inputKey]; 
  41.     if (inputKey) { 
  42.         DebugLog(@"inputStr_get:%@",[[self shareInputStrDict] objectForKey:inputKey]); 
  43.         return [[self shareInputStrDict] objectForKey:inputKey]; 
  44.     } 
  45.     return nil; 
  46.  
  47. - (void)deleteInputData{ 
  48.     NSString *inputKey = [self inputKey]; 
  49.     DebugLog(@"inputKey_delegate:%@",inputKey); 
  50.     if (inputKey) { 
  51.         [[self shareInputStrDict] removeObjectForKey:inputKey]; 
  52.         [[self shareInputMediaDict] removeObjectForKey:inputKey]; 
  53.     } 
  54.  
  55. - (void)saveInputStr{ 
  56.     NSString *inputStr = _inputTextView.text; 
  57.     NSString *inputKey = [self inputKey]; 
  58.     DebugLog(@"inputKey_save:%@",inputKey); 
  59.     if (inputKey && inputKey.length > 0) { 
  60.         if (inputStr && inputStr.length > 0) { 
  61.             [[self shareInputStrDict] setObject:inputStr forKey:inputKey]; 
  62.         }else{ 
  63.             [[self shareInputStrDict] removeObjectForKey:inputKey]; 
  64.         } 
  65.     } 
  66.  
  67. - (void)saveInputMedia{ 
  68.     NSString *inputKey = [self inputKey]; 
  69.     if (inputKey && inputKey.length > 0) { 
  70.         if (_mediaList.count > 0) { 
  71.             [[self shareInputMediaDict] setObject:_mediaList forKey:inputKey]; 
  72.         }else{ 
  73.             [[self shareInputMediaDict] removeObjectForKey:inputKey]; 
  74.         } 
  75.     } 
  76.  
  77. - (NSMutableArray *)inputMedia{ 
  78.     NSString *inputKey = [self inputKey]; 
  79.     if (inputKey) { 
  80.         return [[self shareInputMediaDict] objectForKey:inputKey]; 
  81.     } 
  82.     return nil; 
  83.  
  84. - (void)setToUser:(User *)toUser{ 
  85.     _toUser = toUser; 
  86.     NSString *inputStr = [self inputStr]; 
  87.     if (_inputTextView) { 
  88.         if (_contentType != UIMessageInputViewContentTypePriMsg) { 
  89.             self.placeHolder = _toUser? [NSString stringWithFormat:@"回复 %@", _toUser.name]: @"撰写评论"; 
  90.         }else{ 
  91.             self.placeHolder = @"请输入私信内容"; 
  92.         } 
  93.        _inputTextView.selectedRange = NSMakeRange(0, _inputTextView.text.length); 
  94.        [_inputTextView insertText:inputStr? inputStr: @""]; 
  95.         
  96.        _mediaList = [self inputMedia]; 
  97.        [self mediaListChenged]; 
  98.    } 

上面无非就是通过聊天对象的名字拼接成key值,然后对应存储当前输入框的字符串到全局static的字典中,然后是取出、删除的几个方法。

3、再看看那哪些地方调用了这些方法:

保 存的方法,放在frame重写的方法里,因为输入框会随着键盘的现实和隐藏而切换frame,不过我公司的项目一开始聊天模块是我同事开发的,我发现他用 Masonry的布局代码去变换输入框的位置,选择了布局约束也就意味着放弃了frame,所以何处调用save方法还是要根据实际需求和实际的编码实 现。另外,其实在最开始开发这个输入框的时候,可以考虑其运作的周期:开始编辑->正在编辑->结束编辑,这些运作周期是可以实现出各自的方 法,就和一个控制器的生命周期一样。总之思路很多,做好是能实现出好管理好维护的逻辑。

然后找找删除的方法,删除的方法是放在将字符串发出去的最前面,因为已经发送出去了,是可以将字典中存储的元素删除了去。

另外,在创建key的时候,这个key字符串是依赖当前聊天对象的,因为当前输入框的内容要和当前好友对象一一对应,不能我保存了当前好友对应的输入框内容,跳到别的好友却又出现了一样的内容。所以key值需要依据当前好友的字符串来决定,所以Coding源码中重写了ToUser属性的set方法:

作者:何杨

来源:51CTO

时间: 2024-10-28 14:14:51

iOS开发之聊天模块--内容保存逻辑实现的相关文章

IOS开发之功能模块--自定义导航控制器类常用自定义的代码

前言:本文篇幅不多,但是涉及到的内容却是开发中常用的. 涉及的内容: 1.统一设置导航控制器子控制器的返回按钮. 2.因为修改了系统的返回按钮,所以还需要设置手势事件. 3.隐藏底部的工具条. 这里直接给出.m的实现文件,.h文件不需要,因为没有属性,没有自定义公开的方法. 1 #import "YMNavigationController.h" 2 3 @interface YMNavigationController () <UIGestureRecognizerDelega

iOS开发入门:编写OCUnit测试方法-逻辑测试方法

应用测试和逻辑测试 添加OCUnit到工程时候,我们提到过,应用测试(Application Testing)和逻辑测试(Logic  Testing)两个概念,它们并非是OCUnit中的概念,而是单元测试中概念.应用测试是对整个应用程序进行的测试,设计测试用例时候要考虑到运行环 境等因素,例如在测试JavaEE时候需要考虑Web容器和EJB容器等环境问题.而逻辑测试则是轻量级的,只测试某个业务逻辑对象的方法或算法正确性. 编写OCUnit测试方法 每一个单元测试用例对应于测试类中的一个方法,因

iOS开发那些事--编写OCUnit测试方法-逻辑测试方法

应用测试和逻辑测试 添加OCUnit到工程时候,我们提到过,应用测试(Application Testing)和逻辑测试(Logic Testing)两个概念,它们并非是OCUnit中的概念,而是单元测试中概念.应用测试是对整个应用程序进行的测试,设计测试用例时候要考虑到运行环境等因素,例如在测试JavaEE时候需要考虑Web容器和EJB容器等环境问题.而逻辑测试则是轻量级的,只测试某个业务逻辑对象的方法或算法正确性. 编写OCUnit测试方法 每一个单元测试用例对应于测试类中的一个方法,因此测

IOS开发之功能模块--自定义UITabBarViewController的备用代码

前言:因为常用,所以我就备份到这里,然后如果需要修改,可以根据需求进行相关的更改. 1 @implementation YMTabBarController 2 3 - (void)viewDidLoad { 4 [super viewDidLoad]; 5 /**** 初始化一些设置 ****/ 6 [self setUp]; 7 8 /**** 添加子控制器 ****/ 9 [self addChildViewControllers]; 10 } 11 - (void)setUp{ 12 1

iOS开发之微信聊天工具栏的封装

之前山寨了一个新浪微博(iOS开发之山寨版新浪微博小结),这几天就山寨个微信吧.之前已经把微信的视图结构简单的拖了一下(IOS开发之微信山寨版),今天就开始给微信加上具体的实现功能,那么就先从微信的聊天界面开始吧.提到封装是少不了写代码的,在封装组件的时候,为了组件的可移植性,我们就不能用storyboard来拖拽了.为了屏幕的适配,适应不同屏幕的手机,所以在封装组件的时候是少不了为我们的组件来添加约束.今天博客中的所有代码都是脱离storyboard的,这些代码在别的工程中也是可以使用的.好,

iOS开发之微信聊天工具栏的封装_IOS

微信大家基本上都用过,今天要做的就是微信的聊天工具条.聊天工具条还是比较复杂的,其中包括发送表情,发送文字,发送图片,发送声音,拍照等等功能,下面给出发送录音,文字,表情的代码,其他的和这几样类似.还是那句话百字不如一图,先来几张效果图吧. 在封装聊天工具条的的时候表情键盘是之前封装好的,所以拿过来就可以用的啦.因为不管是工具条还是表情键盘都是用约束来控件大小的,所以横屏也是没问题的,在大屏手机上也是没问题的.下面将会一步步讲解如何封装下面的聊天工具条.主要是对工具条的封装,表情键盘在这就不做讲

iOS开发之微信聊天页面实现

在上篇博客(iOS开发之微信聊天工具栏的封装)中对微信聊天页面下方的工具栏进行了封装,本篇博客中就使用之前封装的工具栏来进行聊天页面的编写.在聊天页面中主要用到了TableView的知识,还有如何在俩天中显示我们发送的表情,具体请参考之前的博客:IOS开发之显示微博表情,在这儿就不做赘述啦.在聊天页面用到了三对,六种Cell,不过cell的复杂度要比之前的新浪微博(IOS开发之新浪围脖)简单的多.废话少说吧,还是先来几张效果图,在给出实现代码吧. 聊天界面的效果图如下:在下面的聊天界面中中用到了

ios开发在表视图显示cell里的内容时出现failed to obtain a cell from its datasource

问题描述 ios开发在表视图显示cell里的内容时出现failed to obtain a cell from its datasource 这是代码 -(NSInteger)tableView:(UITableView )tableView numberOfRowsInSection:(NSInteger)section{ return 1; } -(UITableViewCell)tableView:(UITableView )tableView cellForRowAtIndexPath:

iOS开发CoreAnimation解读之四——Layer层动画内容

iOS开发CoreAnimation解读之四--Layer层动画内容 一.引言         通过前几篇博客的介绍,我们可以了解到layer层可以设置许多与控件UI相关的属性,并且对于iOS开发,UIView层的属性是会映射到CALayer的,因此,可以通过UIKit和CoreAnimation两个框架来设置控件的UI相关属性,当属性发生变化时,我们可以使其展示一个动画效果. 二.CAAnimation动画体系的介绍         CAAnimation是CoreAnimation框架中执行