需求详解:
在实际开发中,有可能是在后期优化的时候,会有这么需要优化的需求:聊天输入框保存之前输入的文本,提高用户的良好体验。
在聊天模块中,用户可能会在输入框输入若干字符,但是没有点击发送就点击退出聊天,或者要点击用户头像确认用户的信息,或者比如需要向好友发送另一个好 友的 ID 不得不暂时退出当前好友聊天界面跳转找到别的界面找 ID,然而当前聊天输入框也已经输入好了若干字符,用户当然不希望退出之后就删除之前输入好的 文字。所以这里就需要暂时保存用户输入好的但是没有发送出去的字符串。
但是,还需要满足 1、完全杀掉或者完全退出应用就需要清楚这个暂时保存的字符串,2、发送出去之后,肯定就要 delegate 之前暂时保存的字符串喽。
开始:
这部分逻辑的实现一开始我没怎么比较好的头绪,只想到本地序列化,但实际上这个还不算是最好的思路,因为本地序列化用到这里有点小题大做了,其实只要用全局静态变量的字典就可以了。
具体实现的逻辑,我也特意阅读研究了 Coding 项目的实现,毕竟这个项目是比较成熟的项目,聊天模块也做的很不错,所以学学别人的思想,正所谓站在巨人的肩膀上,也是很好的哦。
那么下面,我就直接解读 Coding 源码 () 在这个聊天模块内容保存的逻辑吧,就不拿自己工作开发的项目来讲了。
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 17 - (NSString * ) inputKey {
- 18 NSString * inputKey = nil;
- 19
- if (_contentType == UIMessageInputViewContentTypePriMsg) {
- 20 inputKey = [NSString stringWithFormat: @"privateMessage_%@", self.toUser.global_key];
- 21
- } else {
- 22
- if (_commentOfId) {
- 23
- switch (_contentType) {
- 24
- case UIMessageInputViewContentTypeTweet:
- 25 inputKey = [NSString stringWithFormat: @"tweet_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0 ? _toUser.global_key: @""];
- 26
- break;
- 27
- case UIMessageInputViewContentTypeTopic:
- 28 inputKey = [NSString stringWithFormat: @"topic_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0 ? _toUser.global_key: @""];
- 29
- break;
- 30
- case UIMessageInputViewContentTypeTask:
- 31 inputKey = [NSString stringWithFormat: @"task_%@_%@", _commentOfId.stringValue, _toUser.global_key.length > 0 ? _toUser.global_key: @""];
- 32
- break;
- 33
- default:
- 34
- break;
- 35
- }
- 36
- }
- 37
- }
- 38
- return inputKey;
- 39
- }
- 40 41 - (NSString * ) inputStr {
- 42 NSString * inputKey = [self inputKey];
- 43
- if (inputKey) {
- 44 DebugLog(@"inputStr_get:%@", [[self shareInputStrDict] objectForKey: inputKey]);
- 45
- return [[self shareInputStrDict] objectForKey: inputKey];
- 46
- }
- 47
- return nil;
- 48
- }
- 49 50 - (void) deleteInputData {
- 51 NSString * inputKey = [self inputKey];
- 52 DebugLog(@"inputKey_delegate:%@", inputKey);
- 53
- if (inputKey) {
- 54[[self shareInputStrDict] removeObjectForKey: inputKey];
- 55[[self shareInputMediaDict] removeObjectForKey: inputKey];
- 56
- }
- 57
- }
- 58 59 - (void) saveInputStr {
- 60 NSString * inputStr = _inputTextView.text;
- 61 NSString * inputKey = [self inputKey];
- 62 DebugLog(@"inputKey_save:%@", inputKey);
- 63
- if (inputKey && inputKey.length > 0) {
- 64
- if (inputStr && inputStr.length > 0) {
- 65[[self shareInputStrDict] setObject: inputStr forKey: inputKey];
- 66
- } else {
- 67[[self shareInputStrDict] removeObjectForKey: inputKey];
- 68
- }
- 69
- }
- 70
- }
- 71 72 - (void) saveInputMedia {
- 73 NSString * inputKey = [self inputKey];
- 74
- if (inputKey && inputKey.length > 0) {
- 75
- if (_mediaList.count > 0) {
- 76[[self shareInputMediaDict] setObject: _mediaList forKey: inputKey];
- 77
- } else {
- 78[[self shareInputMediaDict] removeObjectForKey: inputKey];
- 79
- }
- 80
- }
- 81
- }
- 82 83 - (NSMutableArray * ) inputMedia {
- 84 NSString * inputKey = [self inputKey];
- 85
- if (inputKey) {
- 86
- return [[self shareInputMediaDict] objectForKey: inputKey];
- 87
- }
- 88
- return nil;
- 89
- }
- 90 91 - (void) setToUser: (User * ) toUser {
- 92 _toUser = toUser;
- 93 NSString * inputStr = [self inputStr];
- 94
- if (_inputTextView) {
- 95
- if (_contentType != UIMessageInputViewContentTypePriMsg) {
- 96 self.placeHolder = _toUser ? [NSString stringWithFormat: @"回复 %@", _toUser.name] : @"撰写评论";
- 97
- } else {
- 98 self.placeHolder = @"请输入私信内容";
- 99
- }
- 100 _inputTextView.selectedRange = NSMakeRange(0, _inputTextView.text.length);
- 101[_inputTextView insertText: inputStr ? inputStr: @""];
- 102 103 _mediaList = [self inputMedia];
- 104[self mediaListChenged];
- 105
- }
- 106
- }
上面无非就是通过聊天对象的名字拼接成 key 值,然后对应存储当前输入框的字符串到全局 static 的字典中,然后是取出、删除的几个方法。
3、再看看那哪些地方调用了这些方法:
保 存的方法,放在 frame 重写的方法里,因为输入框会随着键盘的现实和隐藏而切换 frame,不过我公司的项目一开始聊天模块是我同事开发的,我发现他用 Masonry 的布局代码去变换输入框的位置,选择了布局约束也就意味着放弃了 frame,所以何处调用 save 方法还是要根据实际需求和实际的编码实 现。另外,其实在最开始开发这个输入框的时候,可以考虑其运作的周期:开始编辑 -> 正在编辑 -> 结束编辑,这些运作周期是可以实现出各自的方 法,就和一个控制器的生命周期一样。总之思路很多,做好是能实现出好管理好维护的逻辑。
然后找找删除的方法,删除的方法是放在将字符串发出去的最前面,因为已经发送出去了,是可以将字典中存储的元素删除了去。
另外,在创建 key 的时候,这个 key 字符串是依赖当前聊天对象的,因为当前输入框的内容要和当前好友对象一一对应,不能我保存了当前好友对应的输入框内容,跳到别的好友却又出现了一样的内容。所以 key 值需要依据当前好友的字符串来决定,所以 Coding 源码中重写了 ToUser 属性的 set 方法:
尊重劳动成果:
来源: http://www.cnblogs.com/goodboy-heyang/p/5782201.html