環(huán)信3.0ios客戶端的集成(十四)

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.06.25

前言

很多app種都集成環(huán)信做第三方信息通訊工具,這里我們就看一下環(huán)信的主要功能和集成方法窑邦。先給出環(huán)信3.0的地址爷速。
感興趣的可以參考:
1. 環(huán)信ios客戶端的集成(一)
2. 環(huán)信ios客戶端的集成(二)
3. 環(huán)信ios客戶端的集成(三)
4. 環(huán)信ios客戶端的集成(四)
5. 環(huán)信ios客戶端的集成(五)
6. 環(huán)信ios客戶端的集成(六)
7. 環(huán)信ios客戶端的集成(七)
8. 環(huán)信ios客戶端的集成(八)
9. 環(huán)信ios客戶端的集成(九)
10. 環(huán)信ios客戶端的集成(十)
11. 環(huán)信ios客戶端的集成(十一)
12. 環(huán)信ios客戶端的集成(十二)
13. 環(huán)信ios客戶端的集成(十三)
這一篇主要說(shuō)一下環(huán)信的 基于環(huán)信3.0的及時(shí)通訊在具體工程上的應(yīng)用

一、環(huán)信的集成

工程里我使用的是pod進(jìn)行集成的持搜,環(huán)信有兩個(gè)版本吉殃,一個(gè)版本是帶語(yǔ)音功能的辞居,另外一個(gè)版本是不帶語(yǔ)音功能的,我集成的是帶語(yǔ)音功能的蛋勺,方便以后項(xiàng)目需求有所擴(kuò)展瓦灶,目前的項(xiàng)目還是用不到語(yǔ)音的。

pod 'Hyphenate'

下面看一下集成后的環(huán)信文檔組織結(jié)構(gòu)抱完。

代碼組織結(jié)構(gòu)-1
代碼組織架構(gòu)-2

二贼陶、環(huán)信的使用

下面就以具體工程為例進(jìn)行具體說(shuō)一下環(huán)信的集成。

單例類管理環(huán)信狀態(tài)

下面新建立一個(gè)環(huán)信單例類乾蛤,在這個(gè)類里的方法主要就是管理登錄狀態(tài)每界,以及幾個(gè)代理的回調(diào)捅僵,包括是否登錄的代理回調(diào)家卖、是否收到消息的代理回調(diào)以及消息是否送達(dá)和讀取的回調(diào)等。
下面看代碼庙楚。

//這個(gè)頭文件繼承自NSObject
#import "JJBaseModel.h"

@interface JJMessageDataTool : NSObject <EMClientDelegate, EMChatManagerDelegate>

//單例
+ (instancetype)shareMessageTool;

//登錄
- (void) loginEMClient;

//退出登陸
- (void) layoutEMClient;

//獲取登陸狀態(tài)
- (BOOL) getLoginStatus;

@end

這里的頭文件上荡,沒(méi)有暴露出是否讀取和有消息的回調(diào)接口,后面會(huì)加上該接口。

#import "JJMessageDataTool.h"

@interface JJMessageDataTool () <EMClientDelegate, EMChatManagerDelegate>

@property (nonatomic, strong) EMClient *client;

@end

@implementation JJMessageDataTool

#pragma mark - Class Public Function

+ (instancetype)shareMessageTool
{
    static JJMessageDataTool *tool = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tool = [[JJMessageDataTool alloc] init];
        EMOptions *options = [EMOptions optionsWithAppkey:@"你的環(huán)信appKey"];
        [[EMClient sharedClient] initializeSDKWithOptions:options];
        [[EMClient sharedClient] addDelegate:tool delegateQueue:nil];   //回調(diào)代理
        [[EMClient sharedClient].chatManager addDelegate:tool delegateQueue:nil];
    });
    return tool;
}

//自動(dòng)登錄回調(diào)

- (void)connectionStateDidChange:(EMConnectionState)aConnectionState 
{
    if (aConnectionState == EMConnectionConnected) {
        NSLog(@"環(huán)信已連接");
    } 
    else {
        NSLog(@" 環(huán)信連接斷開(kāi)");
    }
}

//會(huì)話列表發(fā)生變化
- (void)conversationListDidUpdate:(NSArray *)aConversationList 
{
    [[NSNotificationCenter defaultCenter] postNotificationName:kJJPrivateMessageListChat object:aConversationList];
}

//收到消息
- (void)messagesDidReceive:(NSArray *)aMessages 
{
    [[NSNotificationCenter defaultCenter] postNotificationName:kJJPrivateMessageChat object:aMessages];
}

//消息已讀
- (void)messagesDidRead:(NSArray *)aMessages 
{

}

//消息已送達(dá)
- (void)messagesDidDeliver:(NSArray *)aMessages 
{

}

//登錄
- (void) loginEMClient 
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        if ([JJConfig getOwnID]) {
            //登錄
            EMError *loginError = [[EMClient sharedClient] loginWithUsername:[JJConfig getOwnID] password:[JJConfig getEasePassword]];
            if (!loginError) {
                [[EMClient sharedClient].options setIsAutoLogin:YES];
                NSLog(@"環(huán)信登錄成功!!!");
            }
            else {
                NSLog(@"環(huán)信登錄失敗,失敗原因是%@",loginError.errorDescription);
            }
        }
    });
}

//退出登陸
- (void) layoutEMClient 
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [[EMClient sharedClient] logout:YES completion:^(EMError *aError) {
            NSLog(@"環(huán)信已退出登陸");
        }];
    });
}

//獲取登陸狀態(tài)
- (BOOL) getLoginStatus 
{
    if ([EMClient sharedClient].currentUsername && [EMClient sharedClient].currentUsername.length > 0) {
        return YES;
    }
    return NO;
}

@end

這個(gè)是個(gè)工具在appDidFinishLaunching的時(shí)候就要初始化酪捡,與app生命周期相同叁征,全局進(jìn)行監(jiān)控和管理。

服務(wù)端和客戶端的分工

我們這里繼承環(huán)信需要服務(wù)端的參與逛薇,但是參與的不是很多捺疼,主要如下:

  • 服務(wù)端負(fù)責(zé)返回給我們環(huán)信的密碼,注冊(cè)是在服務(wù)端做的永罚;
  • 客戶端進(jìn)行其他方面的UI以及邏輯控制啤呼。
    我們客戶端向自己的服務(wù)器請(qǐng)求,獲取環(huán)信的密碼呢袱。

這里客戶端有幾點(diǎn)要主要注意:

  • 我們這邊是登錄的時(shí)候官扣,服務(wù)器會(huì)返回給我們環(huán)信密碼,而我們登錄分為三方以及手機(jī)號(hào)登錄羞福,因此惕蹄,要在這兩個(gè)地方保存返回的環(huán)信密碼,保存在沙盒治专。
userInfo.easePasswordStr = [dataDict objectForKey:@"easemobPassword"];

//環(huán)信登錄卖陵,在本app登錄成功后登錄環(huán)信
[[ZBMessageDataTool shareMessageTool] loginEMClient];

將這個(gè)字典在兩處登錄成功以后保存,然后以字典的形式保存在偏好設(shè)置里面看靠。

但是app在啟動(dòng)方法里面- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions也要判斷登錄狀態(tài)赶促,如果沒(méi)有登錄,要進(jìn)行登錄挟炬,同樣是用上面的單例進(jìn)行登錄管理工作鸥滨。

1. AppDelegate.m
    if ([[JMessageDataTool shareMessageTool] getLoginStatus]) {
        //已自動(dòng)登錄
        NSLog(@"環(huán)信自動(dòng)登錄");
    } 
    else {
        [[JJMessageDataTool shareMessageTool] loginEMClient];
    }

登錄好了,下面就是客戶端的工作了谤祖。

客戶端的實(shí)現(xiàn)

下面就是我們的重頭戲婿滓,那就是客戶端的實(shí)現(xiàn)了,前面登錄邏輯以及其他的集成管理都做好了粥喜,下面就是客戶端的事了凸主。我們點(diǎn)擊用戶頭像,然后在點(diǎn)擊發(fā)消息的按鈕额湘,就可以發(fā)送消息了卿吐。

下面先準(zhǔn)備下數(shù)據(jù)。

- (void)contactChatButtonDidClick:(JJUIButton *)button
{
    NSLog(@"發(fā)送消息的按鈕被點(diǎn)擊了");
    
    JJChatViewController *chatVC = [[JJChatViewController alloc] init];
    JJMessageModel *messageModel = [[JJMessageModel alloc] init];
    messageModel.toUserName = self.userModel.userNickname?:@"";
    messageModel.uname = [JJConfig getOwnNicename]?:@"";
    messageModel.uhead = [JJConfig myProfile].avatar?:@"";
    messageModel.toUserHead = self.userModel.userAvatar?:@"";
    chatVC.conversationId = [NSString stringWithFormat:@"%ld", self.userModel.userId];
    chatVC.messageModel = messageModel;
    chatVC.title = self.userModel.userNickname;

    [self.navigationController pushViewController:chatVC animated:YES];
}

這里JJChatViewController是聊天室锋华,JJMessageModel這個(gè)是聊天數(shù)據(jù)模型嗡官。下面看一下數(shù)據(jù)模型。

#import <Foundation/Foundation.h>
#import "JJMessageChatModel.h"

//私信模型

@interface JJMessageModel : JJBaseModel

@property (nonatomic, copy) NSString *lastMessage;                      //最后一條消息
@property (nonatomic, copy) NSString *uname;                            //發(fā)送者昵稱
@property (nonatomic, copy) NSString *uhead;                            //發(fā)送者頭像
@property (nonatomic, copy) NSString *toUserName;                       //接受者名稱
@property (nonatomic, copy) NSString *toUserHead;                       //接受者頭像
@property (nonatomic, copy) NSString *un_read_num;                      //未讀數(shù)量
@property (nonatomic, copy) NSString *imgPath;
@property (nonatomic, copy) NSString *conversationId;

+ (instancetype)shareMessageModel;

@end

下面我們看一下聊天室JJChatViewController毯焕。

1. JJChatViewController.h

#import "JJBaseVC.h"

@class JJMessageModel;

//聊天界面
@interface JJChatViewController : JJBaseVC

@property (nonatomic, strong) JJMessageModel *messageModel;
@property (nonatomic, copy) NSString *conversationId;

@end

2. JJChatViewController.m
#import "JJChatViewController.h"
#import "JJMessageChatCell.h"
#import "JJMessageModel.h"
#import "JJMessageDataTool.h"
#import "JJPersonCenterContainVC.h"

@interface JJChatViewController () <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, EMChatManagerDelegate, UIImagePickerControllerDelegate, JJMessageChatCellDelegate, JJChatSendCollectionDelegate>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray <JJChatModelFrame *>*chatArray;
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UIView *sendView;
@property (nonatomic, assign) long long lastTime;
@property (nonatomic, assign) CGFloat kbHeight;
@property (nonatomic, strong) JJUIView *backView;
@property (nonatomic, strong) UIImage *sendImage;

@end

@implementation JJChatViewController

static NSString * const JJMessageChatCellID = @"JJMessageChatCellID";

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    if (![[JJMessageDataTool shareMessageTool] getLoginStatus]) {
        [[JJMessageDataTool shareMessageTool] loginEMClient];
    }
    self.view.backgroundColor = [UIColor colorWithHexString:@"#F1F2F3"];

    self.chatArray = [NSMutableArray array];
    //創(chuàng)建回話
    [self creatSession];
    
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kJJCommonScreenWidth, kJJCommonScreenHeight - 50) style:UITableViewStylePlain];
    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    _tableView.backgroundColor = [UIColor colorWithHexString:@"#F1F2F3"];
    [self.view addSubview:_tableView];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [_tableView registerClass:[JMessageChatCell class] forCellReuseIdentifier:JJMessageChatCellID];
    
    self.sendView.frame = CGRectMake(0, kJJCommonScreenHeight - 50, kJJCommonScreenWidth, 50);
    self.sendView.backgroundColor = [UIColor whiteColor];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceivedMessages:) name:kJJPrivateMessageChat object:nil];
    
}

- (void)viewWillAppear:(BOOL)animated 
{
    [super viewWillAppear:animated];

    self.navigationController.navigationBarHidden = NO;
}


- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    NSLog(@"%s",__FUNCTION__);
}

#pragma mark - Object Private Function

- (UIView *)sendView
{
    if (!_sendView) {
        _sendView = [[UIView alloc] init];
        [self.view addSubview:_sendView];
        _textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 5, kJJCommonScreenWidth - 70, 40)];
        [_sendView addSubview:_textField];
        _textField.borderStyle = UITextBorderStyleRoundedRect;
        _textField.placeholder = @"輸入新消息";
        _textField.returnKeyType = UIReturnKeyDone;
        _textField.delegate = self;
        
        //加號(hào)按鈕
        JJUIButton *moreButton = [JJUIButton buttonWithType:UIButtonTypeCustom];
        [moreButton setImage:[UIImage imageNamed:@"chat_more"] forState:UIControlStateNormal];
        [moreButton addTarget:self action:@selector(moreButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
        [_sendView addSubview:moreButton];
        
        [moreButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerY.equalTo(_textField);
            make.left.equalTo(_textField.mas_right).offset(10.0);
            make.width.height.equalTo(@(CGRectGetHeight(_textField.frame)));
        }];
    }
    return _sendView;
}

- (void)endEdit
{
    if (self.textField.text.length == 0) {
        return;
    }
    
    //發(fā)送出去
    [self sendMessageWithMessage:self.textField.text andType:nil];
    self.textField.text = @"";
}

- (void)keyboardWillShow:(NSNotification *)notification
{
    CGFloat kbHeight = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    self.kbHeight = kbHeight;
    // 取得鍵盤的動(dòng)畫時(shí)間衍腥,這樣可以在視圖上移的時(shí)候更連貫
    NSTimeInterval duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:duration animations:^{
        //按鈕上移
        self.tableView.frame = CGRectMake(0, 0, kJJCommonScreenWidth, kJJCommonScreenHeight - 50 - kbHeight);
        self.sendView.frame = CGRectMake(0, kJJCommonScreenHeight - 50 - kbHeight, kJJCommonScreenWidth, 50);
        if (self.tableView.contentSize.height > self.tableView.height) {
            [self.tableView scrollToBottom];
        }
    } completion:^(BOOL finished) {
        
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    // 取得鍵盤的動(dòng)畫時(shí)間,這樣可以在視圖上移的時(shí)候更連貫
    NSTimeInterval duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    
    [UIView animateWithDuration:duration animations:^{
        self.tableView.frame = CGRectMake(0, 0, kJJCommonScreenWidth, kJCommonScreenHeight - 50);
        self.sendView.frame = CGRectMake(0, kJJCommonScreenHeight - 50, kJJCommonScreenWidth, 50);
        if (self.tableView.contentSize.height > self.tableView.height) {
            [self.tableView scrollToBottom];
        }
    } completion:^(BOOL finished) {
        
    }];
}

//判斷前后時(shí)間是否一致

- (BOOL)timeIsEqualInOneHour:(long long )comStrTime
{
    NSString *current = [self exchangeTimeFrom:comStrTime];
    JJChatModelFrame *chatModelFrame = [self.chatArray lastObject];
    NSString *last = [self exchangeTimeFrom:chatModelFrame.messageModel.timestamp];
    if ([current isEqualToString:last]) {
        return YES;
    }
    return NO;
}

- (NSString*)exchangeTimeFrom:(long long)timeStamp
{
    NSDate *timeDate = [[NSDate alloc]initWithTimeIntervalSince1970:timeStamp/1000];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy年MM月dd日 HH";
    NSString *timeStr = [dateFormatter stringFromDate:timeDate];
    return timeStr;
}

//創(chuàng)建會(huì)話,讀取歷史消息

- (void)creatSession
{
    if (self.chatArray.count > 0) {
        [self.chatArray removeAllObjects];
    }
    EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:self.conversationId type:EMConversationTypeChat createIfNotExist:YES];
    long long timestamp = 0;//拿來(lái)所有聊天記錄
    long long toTimeStamp = [NSDate getDateTimeTOMilliSeconds:[NSDate dateWithTimeIntervalSinceNow:0]];
    int MAX_ITEM = 1000;
    
    [conversation loadMessagesFrom:timestamp to:toTimeStamp count:MAX_ITEM completion:^(NSArray *aMessages, EMError *aError) {
        if (!aError) {
            {
                for (EMMessage *message in aMessages) {
                    EMMessageBody *msgBody = message.body;
                    switch (msgBody.type) {
                        case EMMessageBodyTypeText://目前只支持文字聊天
                        {
                            // 收到的文字消息
                            EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
                            NSString *chatContent_text = textBody.text;
                            
                            JJMessageChatModel *messageModel  = [[JJMessageChatModel alloc]init];
                            if (message.direction == EMMessageDirectionSend) {
                                messageModel.messageDirection = MessageDirectionSend;
                            }
                            else {
                                messageModel.messageDirection = MessageDirectionReceive;
                            }
                            messageModel.avatar = @"";
                            messageModel.messageId = message.messageId;
                            messageModel.timestamp = message.timestamp;
                            messageModel.messageContent = chatContent_text;
                            messageModel.remoteImageUrl = nil;
                            messageModel.image = nil;
                            messageModel.type = [[message.ext valueForKey:@"type"] intValue];
                            if (messageModel.type == 2) {
                                messageModel.liveModel = [JJLiveModel modelWithDictionary:message.ext];
                            } else if (messageModel.type == 1){
                                messageModel.videoModel = [JJShortVideoModel modelWithDictionary:message.ext];
                            }
                           
                            BOOL isEqual = NO;
                            
                            if (self.chatArray) {
                                isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
                            }
                            
                            JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
                            chatModelFrame.type = [[message.ext valueForKey:@"type"] intValue];
                            self.lastTime = message.timestamp;
                            if (chatModelFrame.messageDirection == MessageDirectionSend) {
                                chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
                            } else {
                                chatModelFrame.messageModel.avatar = self.messageModel.uhead;
                            }
                            [self.chatArray addObject:chatModelFrame];
                        }
                            break;
                        case EMMessageBodyTypeImage:{
                            // 收到的圖片消息
                            EMImageMessageBody *imageBody = (EMImageMessageBody *)msgBody;
                            JJMessageChatModel *messageModel  = [[JJMessageChatModel alloc]init];
                            if (message.direction == EMMessageDirectionSend) {
                                messageModel.messageDirection = MessageDirectionSend;
                            }
                            else {
                                messageModel.messageDirection = MessageDirectionReceive;
                            }
                            messageModel.avatar = @"";
                            messageModel.messageId = message.messageId;
                            messageModel.messageContent = nil;
                            messageModel.localImageUrl = imageBody.localPath;
                            messageModel.remoteImageUrl = imageBody.remotePath;
                            messageModel.timestamp = message.timestamp;
                            messageModel.imaageSize = imageBody.size;
                            messageModel.type = 3;
                            
                            BOOL isEqual = NO;
                            
                            if (self.chatArray) {
                                isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
                            }
                            JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
                            chatModelFrame.type = 3;
                            self.lastTime = message.timestamp;
                            if (chatModelFrame.messageDirection == MessageDirectionSend) {
                                chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
                            } else {
                                chatModelFrame.messageModel.avatar = self.messageModel.uhead;
                            }
                            [self.chatArray addObject:chatModelFrame];
                        }
                            break;
                        default:
                            break;
                    }
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    if (self.tableView.contentSize.height > self.tableView.height) {
                        [self.tableView scrollToBottom];
                    }
                });
            }
        }
    }];

}

//文本消息的發(fā)送

- (void)sendMessageWithMessage:(NSString *)messageStr andType:(NSMutableDictionary *)param;
{
    if (messageStr.length > 0 || param.count > 0) {
        
        if (!param) {
            param = [[NSMutableDictionary alloc] init];
        }
        [param setObject:[JJConfig getOwnNicename]?:@"" forKey:@"uname"];
        [param setObject:[JJConfig myProfile].avatar?:@"" forKey:@"uhead"];
        if (messageStr && messageStr.length > 0) {
            [param setObject:@"0" forKey:@"type"];
        }
        if (_messageModel) {
            [param setObject:_messageModel.toUserHead?:@"" forKey:@"toUserHead"];
            [param setObject:_messageModel.toUserName?:@"" forKey:@"toUserName"];
        }
        
        EMTextMessageBody *messageBody = [[EMTextMessageBody alloc] initWithText:messageStr];
        EMMessage *message = [[EMMessage alloc] initWithConversationID:self.conversationId from:[JJConfig getOwnID] to:self.conversationId body:messageBody ext:param];
        message.chatType = EMChatTypeChat;
        message.direction = EMMessageDirectionSend;
        NSLog(@"%@", message.ext);
        //發(fā)送消息
        [[EMClient sharedClient].chatManager sendMessage:message progress:^(int progress) {
            
        } completion:^(EMMessage *message, EMError *error) {
            message.chatType = EMChatTypeChat;
            EMMessageBody *msgBody = message.body;
            if (!error) {
                
                //發(fā)送的是文字消息
                EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
                JJMessageChatModel *messageModel = [[JJMessageChatModel alloc] init];
                if (message.direction == EMMessageDirectionSend) {
                    messageModel.messageDirection = MessageDirectionSend;
                }
                else {
                    messageModel.messageDirection = MessageDirectionReceive;
                }
                messageModel.avatar = @"";
                messageModel.messageId = message.messageId;
                messageModel.messageContent = textBody.text;
                messageModel.timestamp = message.timestamp;
                messageModel.type = [[message.ext valueForKey:@"type"] intValue];
                if (messageModel.type == 2) {
                    messageModel.liveModel = [JJLiveModel modelWithDictionary:message.ext];
                } else if (messageModel.type == 1){
                    messageModel.videoModel = [JJShortVideoModel modelWithDictionary:message.ext];
                }
                
                DDLogVerbose(@"發(fā)送==%@",messageModel.messageContent);
                DDLogVerbose(@"發(fā)送給對(duì)方ID==%@",self.conversationId);
                
                BOOL isEqual = NO;
                if (self.chatArray) {
                    isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
                }
                JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
                self.lastTime = message.timestamp;
                chatModelFrame.type = [[message.ext valueForKey:@"type"] intValue];
                if (chatModelFrame.messageDirection == MessageDirectionSend) {
                    chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
                } else {
                    chatModelFrame.messageModel.avatar = self.messageModel.uhead;
                }
                [self.chatArray addObject:chatModelFrame];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    [self.tableView scrollToRow:self.chatArray.count - 1 inSection:0 atScrollPosition:UITableViewScrollPositionBottom animated:YES];
                });
            }
            else {
             DDLogVerbose(@"錯(cuò)誤描述==%@",error.errorDescription);
            }
        }];
    }
}

//對(duì)象轉(zhuǎn)換為字典的方法

- (NSMutableDictionary *)returnToDictionaryWithModel:(JJMessageModel *)model
{
    NSMutableDictionary *userDic = [NSMutableDictionary dictionary];
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList([JJMessageModel class], &count);
    for (int i = 0; i < count; i++) {
        const char *name = property_getName(properties[i]);
        
        NSString *propertyName = [NSString stringWithUTF8String:name];
        id propertyValue = [model valueForKey:propertyName];
        if (propertyValue) {
            [userDic setObject:propertyValue forKey:propertyName];
        }
    }
    free(properties);
    
    return userDic;
}

//圖片消息的發(fā)送

- (void)sendImageMessage
{
    if (self.sendImage) {
        NSMutableDictionary *param = [[NSMutableDictionary alloc] init];
        [param setObject:[JJConfig getOwnNicename]?:@"" forKey:@"uname"];
        [param setObject:[JJConfig myProfile].avatar?:@"" forKey:@"uhead"];
        [param setObject:@"3" forKey:@"type"];
        if (_messageModel) {
            [param setObject:_messageModel.toUserHead?:@"" forKey:@"toUserHead"];
            [param setObject:_messageModel.toUserName?:@"" forKey:@"toUserName"];
        }

        NSData *imageData = UIImageJPEGRepresentation(self.sendImage, 1);
        EMImageMessageBody *imageMessageBody = [[EMImageMessageBody alloc] initWithData:imageData displayName:nil];
        EMMessage *imageMessage = [[EMMessage alloc] initWithConversationID:self.conversationId from:[JJConfig getOwnID] to:self.conversationId body:imageMessageBody ext:param];
        
        imageMessage.chatType = EMChatTypeChat;
        imageMessage.direction = EMMessageDirectionSend;
        
        [[EMClient sharedClient].chatManager sendMessage:imageMessage progress:^(int progress) {
            
        } completion:^(EMMessage *message, EMError *error) {
            
            if (!error) {
                NSLog(@"發(fā)送圖片消息");
                JJMessageChatModel *messageModel = [[JJMessageChatModel alloc] init];
                if (message.direction == EMMessageDirectionSend) {
                    messageModel.messageDirection = MessageDirectionSend;
                }
                else {
                    messageModel.messageDirection = MessageDirectionReceive;
                }
                messageModel.avatar = @"";
                messageModel.messageId = message.messageId;
                messageModel.timestamp = message.timestamp;
                messageModel.type = 3;
                messageModel.imaageSize = self.sendImage.size;
                messageModel.image = self.sendImage;
                DDLogVerbose(@"發(fā)送==%@",messageModel.messageContent);
                DDLogVerbose(@"發(fā)送給對(duì)方ID==%@",self.conversationId);
                
                BOOL isEqual = NO;
                if (self.chatArray) {
                    isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
                }
                JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
                chatModelFrame.type = 3;
                self.lastTime = message.timestamp;
                if (chatModelFrame.messageDirection == MessageDirectionSend) {
                    chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
                } else {
                    chatModelFrame.messageModel.avatar = self.messageModel.uhead;
                }
                [self.chatArray addObject:chatModelFrame];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    [self.tableView scrollToRow:self.chatArray.count - 1 inSection:0 atScrollPosition:UITableViewScrollPositionBottom animated:YES];
                    
                });
            } 
        }];
    }
}

//加載接收的消息

- (void)loadReceivedMessageWithArray:(NSArray *)messageArr
{
    if (messageArr.count > 0) {
        for (EMMessage *message in messageArr) {
            if (![message.conversationId isEqualToString:_conversationId]) {
                return;
            }
            EMMessageBody *msgBody = message.body;
            self.messageModel.toUserHead = [message.ext objectForKey:@"toUserHead"];
            self.messageModel.toUserName = [message.ext objectForKey:@"toUserName"];
            self.messageModel.uhead = [message.ext objectForKey:@"uhead"];
            self.messageModel.uname = [message.ext objectForKey:@"uname"];
            switch (msgBody.type) {
                    
                 //文字
                case EMMessageBodyTypeText:
                {
                    // 收到的文字消息
                    EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
                    NSString *chatDetailtext = textBody.text;
                    JJMessageChatModel *messageModel  = [[JJMessageChatModel alloc] init];
                    if (message.direction == EMMessageDirectionSend) {
                        messageModel.messageDirection = MessageDirectionSend;
                    }
                    else {
                        messageModel.messageDirection = MessageDirectionReceive;
                    }
                    messageModel.avatar = @"";
                    messageModel.messageId = message.messageId;
                    messageModel.messageContent = chatDetailtext;
                    messageModel.timestamp = message.timestamp;
                    messageModel.type = [[message.ext valueForKey:@"type"] intValue];
                    messageModel.image = nil;
                    messageModel.remoteImageUrl = nil;
                    messageModel.localImageUrl = nil;
                    if (messageModel.type == 2) {
                        messageModel.liveModel = [JJLiveModel modelWithDictionary:message.ext];
                    } else if (messageModel.type == 1){
                        messageModel.videoModel = [JJShortVideoModel modelWithDictionary:message.ext];
                    }
                    BOOL isEqual = NO;
                    
                    if (self.chatArray) {
                        isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
                    }
                    JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
                    chatModelFrame.type = [[message.ext valueForKey:@"type"] intValue];
                    self.lastTime = message.timestamp;
                    if (chatModelFrame.messageDirection == MessageDirectionSend) {
                        chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
                    } else {
                        chatModelFrame.messageModel.avatar = self.messageModel.uhead;
                    }
                    [self.chatArray addObject:chatModelFrame];
                    
                    [self.tableView reloadData];
                    [self.tableView scrollToRow:self.chatArray.count - 1 inSection:0 atScrollPosition:UITableViewScrollPositionBottom animated:YES];
                    
                }
                    
                    break;
                    
                //圖片
                case EMMessageBodyTypeImage:
                {
                    [self performSelector:@selector(loadImageMessage:) withObject:message afterDelay:2.0f];
//                    [self loadImageMessage:message];
                }
                break;
                default:
                    break;
            }
        }
    }
}

- (void) loadImageMessage:(EMMessage *)message {
    EMMessageBody *msgBody = message.body;
    EMImageMessageBody *imageBody = (EMImageMessageBody *)msgBody;
    
    JJMessageChatModel *messageModel  = [[JJMessageChatModel alloc] init];
    if (message.direction == EMMessageDirectionSend) {
        messageModel.messageDirection = MessageDirectionSend;
    }
    else {
        messageModel.messageDirection = MessageDirectionReceive;
    }
    messageModel.avatar = @"";
    messageModel.messageId = message.messageId;
    messageModel.timestamp = message.timestamp;
    messageModel.localImageUrl = imageBody.localPath;
    messageModel.remoteImageUrl = imageBody.remotePath;
    messageModel.imaageSize = imageBody.size;
    messageModel.messageContent = nil;
    messageModel.type = 3;
    BOOL isEqual = NO;
    
    if (self.chatArray) {
        isEqual = [self timeIsEqualInOneHour:messageModel.timestamp];
    }
    JJChatModelFrame *chatModelFrame = [[JJChatModelFrame alloc] initWithFrameModel:messageModel timestamp:self.lastTime];
    chatModelFrame.type = 3;
    self.lastTime = message.timestamp;
    if (chatModelFrame.messageDirection == MessageDirectionSend) {
        chatModelFrame.messageModel.avatar = self.messageModel.toUserHead;
    } else {
        chatModelFrame.messageModel.avatar = self.messageModel.uhead;
    }
    [self.chatArray addObject:chatModelFrame];
    
    [self.tableView reloadData];
    [self.tableView scrollToRow:self.chatArray.count - 1 inSection:0 atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

- (void)loadMoreView
{
    [UIView animateWithDuration:0.25 animations:^{
        //背景View
        JJUIView *backView = [[JJUIView alloc] initWithFrame:CGRectMake(0.0, kJJCommonScreenHeight - 432.0/2, kJJCommonScreenWidth, 432.0/2)];
        self.tableView.frame = CGRectMake(0, 0, kJJCommonScreenWidth, kJJCommonScreenHeight - 50 - 432.0/2);
        backView.backgroundColor = [UIColor lightTextColor];
        self.backView = backView;
        [self.view addSubview:backView];
        
        //圖片圖片
        JJUIButton *pictureButton = [JJUIButton buttonWithType:UIButtonTypeCustom];
        [pictureButton setImage:[UIImage imageNamed:@"chat_image"] forState:UIControlStateNormal];
        [pictureButton addTarget:self action:@selector(pictureButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.backView addSubview:pictureButton];
        
        [pictureButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.backView).offset(44/2);
            make.top.equalTo(self.backView).offset(39.0f/2);
            make.width.height.equalTo(@50);
        }];
        
        //圖片文字
        JJUILabel *pictureLabel = [[JJUILabel alloc] init];
        pictureLabel.text = @"圖片";
        pictureLabel.textColor = [UIColor colorWithHexString:@"999999"];
        pictureLabel.font = [UIFont fontWithName:kPingFangSC_Regular size:24/2];
        [self.backView addSubview:pictureLabel];
        
        [pictureLabel sizeToFit];
        [pictureLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(pictureButton.mas_bottom).offset(10.0);
            make.centerX.equalTo(pictureButton);
        }];
        
        //收藏圖片
        JJUIButton *storeButton = [JJUIButton buttonWithType:UIButtonTypeCustom];
        [storeButton setImage:[UIImage imageNamed:@"chat_collection"] forState:UIControlStateNormal];
        [storeButton addTarget:self action:@selector(storeButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.backView addSubview:storeButton];
        
        [storeButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(pictureButton.mas_right).offset(88/2);
            make.top.equalTo(pictureButton);
            make.width.height.equalTo(@50);
        }];
        
        //收藏文字
        JJUILabel *storeLabel = [[JJUILabel alloc] init];
        storeLabel.text = @"收藏";
        storeLabel.textColor = [UIColor colorWithHexString:@"999999"];
        storeLabel.font = [UIFont fontWithName:kPingFangSC_Regular size:24/2];
        [self.backView addSubview:storeLabel];
        
        [storeLabel sizeToFit];
        [storeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(pictureLabel);
            make.centerX.equalTo(storeButton);
        }];
    } completion:^(BOOL finished) {
        
    }];
}

#pragma mark - Action && Notification

- (void)didReceivedMessages:(NSNotification *)noti
{
    NSArray *messageArr = (NSArray *)noti.object;
    [self loadReceivedMessageWithArray:messageArr];
}

- (void)storeButtonDidClick:(JJUIButton *)storeButton
{
    NSLog(@"收藏按鈕被點(diǎn)擊了");
    JJPersonCenterContainVC *nextVC = [[JJPersonCenterContainVC alloc] init];
    nextVC.isChat = YES;
    nextVC.delegate = self;
    [self.navigationController pushViewController:nextVC animated:YES];
}

- (void)pictureButtonDidClick:(JJUIButton *)pictureButton
{
    NSLog(@"圖片按鈕被點(diǎn)擊了");
    
    UIImagePickerController *imagePickerVC = [[UIImagePickerController alloc] init];
    imagePickerVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    imagePickerVC.allowsEditing = YES;
    imagePickerVC.delegate = self;
    [self presentViewController:imagePickerVC animated:YES completion:nil];
}

- (void)moreButtonDidClick:(JJUIButton *)moreButton
{
    [self.textField resignFirstResponder];
    
    if (self.backView) {
        [self.backView removeFromSuperview];
    }
    
    [UIView animateWithDuration:0.25 animations:^{
        //按鈕上移
        self.tableView.frame = CGRectMake(0, 0, kJJCommonScreenWidth, kJJCommonScreenHeight - 50 - 432/2);
        self.sendView.frame = CGRectMake(0, kJJCommonScreenHeight - 50 - 432/2, kJJCommonScreenWidth, 50);
        if (self.tableView.contentSize.height > self.tableView.height) {
            [self.tableView scrollToBottom];
        }
    } completion:^(BOOL finished) {
        
    }];
    
    [self loadMoreView];
}

#pragma mark - UITableViewDelegate, UITableViewDataSource

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JJMessageChatCell *cell = [tableView dequeueReusableCellWithIdentifier:JJMessageChatCellID forIndexPath:indexPath];
    cell.delegate = self;
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.chatModelFrame = self.chatArray[indexPath.row];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JJChatModelFrame *chatModelFrame = self.chatArray[indexPath.row];
    return chatModelFrame.cellHeight;
}

- (void)didClickImagePlusImage:(UIImage *)image{
    if (image) {
        UIButton *btn = [[UIButton alloc] initWithFrame:self.view.frame];
        [btn setBackgroundColor:[UIColor blackColor]];
        [btn setImage:image forState:UIControlStateNormal];
        btn.alpha = 0;
        [btn addTarget:self action:@selector(didClickHiddenImageView:) forControlEvents:UIControlEventTouchUpInside];
        [[UIApplication sharedApplication].keyWindow addSubview:btn];
        [UIView animateWithDuration:0.25 animations:^{
            btn.alpha = 1;
        }];
    }
}

- (void) didClickHiddenImageView:(UIButton *)sender {
    [UIView animateWithDuration:0.25 animations:^{
        sender.alpha = 0;
    } completion:^(BOOL finished) {
        [sender removeFromSuperview];
    }];
}

#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [self endEdit];
    return YES;
}

#pragma mark - UIImagePickerControllerDelegate

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    [picker dismissViewControllerAnimated:YES completion:nil];
    self.sendImage = info[UIImagePickerControllerOriginalImage];
    
    //發(fā)送圖片消息
    [self sendImageMessage];
}

@end

這里還有幾個(gè)類需要說(shuō)明一下婆咸。
首先要說(shuō)的是JJMessageChatModel這個(gè)類竹捉,這個(gè)類的作用就是存放聊天室每個(gè)cell里面的數(shù)據(jù)模型。

#import <Foundation/Foundation.h>
#import "JJLiveModel.h"
#import "JJShortVideoModel.h"

typedef NS_ENUM(NSInteger ,MessageDirection)
{
    MessageDirectionSend = 1,    //發(fā)送消息
    MessageDirectionReceive      //接受消息
    
};

//聊天模型

@interface JJMessageChatModel : JJBaseModel

@property (nonatomic, copy) NSString *avatar;                       //頭像
@property (nonatomic, assign) MessageDirection messageDirection;    //消息來(lái)源類型
@property (nonatomic, copy) NSString *messageId;                    //消息id;
@property (nonatomic, copy) NSString *messageContent;               //文本消息尚骄;
@property (nonatomic, assign) long long timestamp;                  //消息時(shí)間戳
@property (nonatomic, copy) NSString *verify_info;                  //認(rèn)證信息
@property (nonatomic, copy) NSString *cornerMark;                   //頭像角標(biāo)
@property (nonatomic, copy) NSString *message;                      //消息
@property (nonatomic, copy) NSString *remoteImageUrl;               //圖片網(wǎng)絡(luò)地址
@property (nonatomic, copy) NSString *localImageUrl;                //圖片沙盒地址
@property (nonatomic, copy) UIImage *image;                         //圖片
@property (nonatomic, assign) CGSize imaageSize;
@property (nonatomic, strong) JJShortVideoModel *videoModel;
@property (nonatomic, strong) JJLiveModel *liveModel;
@property (nonatomic, assign) int type;

@end

下面還有個(gè)類就是JJChatModelFrame块差,這個(gè)類的作用就是負(fù)責(zé)給每一個(gè)cell賦值并調(diào)整每一個(gè)cell的大小,如下所示:

1. JJChatModelFrame.h
#import <Foundation/Foundation.h>
#import "JJMessageViewController.h"
#import "JJMessageChatModel.h"

#define ChatHeadImage_height  42.0f
#define TimeLabel_height  20.0f

@interface JJChatModelFrame : NSObject

/** 時(shí)間的Frame */
@property (nonatomic,assign)CGRect timeLabelFrame;

/** 頭像的Frame */
@property (nonatomic,assign)CGRect headImageFrame;

/** 聊天內(nèi)容的Frame */
@property (nonatomic,assign)CGRect contentFrame;

/** 認(rèn)證標(biāo)志的Frame */
@property (nonatomic,assign)CGRect verifyBadgeFrame;

/** 消息來(lái)源類型 */
@property (nonatomic,assign) MessageDirection messageDirection;

/** 模型數(shù)據(jù) */
@property (nonatomic,strong) JJMessageChatModel *messageModel;

/*cell的高度 */
@property (nonatomic,assign)CGFloat cellHeight;

@property (nonatomic, assign) int type;                             //1. 文字倔丈,2. 節(jié)目   3. 創(chuàng)意視頻 4. 圖片

/** 通過(guò)模型數(shù)據(jù)計(jì)算出對(duì)應(yīng)的Frame,并且返回出modelFrame自己這個(gè)對(duì)象 */
- (instancetype)initWithFrameModel:model timestamp:(NSTimeInterval)timestamp;

//和上面同理
+ (instancetype)modelFrame:(JJMessageChatModel *)messageModel timestamp:(NSTimeInterval)timestamp;

@end

2. JJChatModelFrame.m
#import "JJChatModelFrame.h"

#define contentFont [UIFont systemFontOfSize:15.0]//聊天消息字體的大小
#define distance 8 //邊距

@implementation JJChatModelFrame

#pragma mark - Object Public Function

- (instancetype)initWithFrameModel:(JJMessageChatModel *)messageModel timestamp:(NSTimeInterval)timestamp
{
    self = [super init];
    if (self) {
        _messageModel = messageModel;
        NSString *timeStr = [self exchangeTimeFrom:messageModel.timestamp];
        NSString *lastStr = [self exchangeTimeFrom:timestamp];
        BOOL timeBool = [timeStr isEqualToString:lastStr];
        CGSize timeSize=[timeStr sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]}]; //通過(guò)時(shí)間NSString計(jì)算出寬度
        if(!timeBool){//前后時(shí)間不相等 不相等顯示憾儒,相等不顯示
            self.timeLabelFrame=CGRectMake(kJJCommonScreenWidth/2.0-(timeSize.width+20)/2.0, 2, timeSize.width+20, TimeLabel_height);//顯示時(shí)間的Frame
        }
        else{
            self.timeLabelFrame=CGRectZero;
        }
        float width, height;
        if (_messageModel.type == 0) {
            CGRect btnRect=[_messageModel.messageContent boundingRectWithSize:CGSizeMake(kJJCommonScreenWidth*0.6, MAXFLOAT)
                                                                      options:NSStringDrawingUsesLineFragmentOrigin
                                                                   attributes:@{NSFontAttributeName:contentFont}
                                                                      context:nil];
            width = btnRect.size.width+20*2;
            height = btnRect.size.height+10*2;
        } else if (_messageModel.type == 1) {
            width = 150;
            height = _messageModel.videoModel.picHeight*150/_messageModel.videoModel.picWidth;
            _messageModel.messageContent = @"這是一個(gè)短視頻";
        } else if (_messageModel.type == 2) {
            width = 389.0f/2;
            height = 320/2;
            _messageModel.messageContent = @"這是一個(gè)節(jié)目";
        } else {
            width = 150;
            height = _messageModel.imaageSize.height*150/_messageModel.imaageSize.width;
        }
        if (_messageModel.messageDirection == MessageDirectionSend) {
            self.headImageFrame = CGRectMake(kJJCommonScreenWidth-distance-ChatHeadImage_height, CGRectGetMaxY(self.timeLabelFrame)+distance, ChatHeadImage_height, ChatHeadImage_height);
            self.contentFrame = CGRectMake(kJJCommonScreenWidth-distance-ChatHeadImage_height-distance-width, CGRectGetMaxY(self.timeLabelFrame)+15, width, height);
            
        }else if (_messageModel.messageDirection == MessageDirectionReceive){
            self.headImageFrame=CGRectMake(distance, CGRectGetMaxY(self.timeLabelFrame)+distance,ChatHeadImage_height, ChatHeadImage_height);
            self.contentFrame=CGRectMake(distance+ChatHeadImage_height+distance, CGRectGetMaxY(self.timeLabelFrame)+15, width, height);
        }
        _messageDirection = messageModel.messageDirection;
        
        if (messageModel.verify_info == nil) {
            _verifyBadgeFrame = CGRectZero;
        }else if (messageModel.verify_info && messageModel.verify_info.length!=0){
            _verifyBadgeFrame =  CGRectMake(CGRectGetMaxX(self.headImageFrame)-13, CGRectGetMaxY(self.headImageFrame)-13, 13, 13);
        }
        
        CGFloat  cellH=MAX(CGRectGetMaxY(self.contentFrame), CGRectGetMaxY(self.headImageFrame));//比較輸入的內(nèi)容和頭像的Y值哪個(gè)大
        if (cellH == NAN) {
            return 0;
        }
        self.cellHeight=cellH+distance;//返回Cell的高度
    }
    return self;
}

#pragma mark - Class Public Function

+ (instancetype)modelFrame:(JJMessageChatModel *)messageModel timestamp:(NSTimeInterval)timestamp{
    return [[self alloc]initWithFrameModel:messageModel timestamp:timestamp];
}

#pragma mark - Object Private Function

- (NSString*)exchangeTimeFrom:(long long)timeStamp
{
    NSDate *timeDate = [[NSDate alloc]initWithTimeIntervalSince1970:timeStamp/1000];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy年MM月dd日 HH:mm";
    NSString *timeStr = [dateFormatter stringFromDate:timeDate];
    return timeStr;
}

@end

還有一個(gè)界面需要說(shuō)的就是,我們聊天室前一個(gè)界面乃沙,那就是消息列表頁(yè)起趾,這個(gè)頁(yè)面主要就是記錄系統(tǒng)消息,以及其他都誰(shuí)給發(fā)過(guò)了消息警儒,方便用戶點(diǎn)擊進(jìn)入聊天室進(jìn)行聊天训裆。下面直接給出代碼了。

//聊天消息列表頁(yè)
1. JJMessageViewController.m
#import "JJMessageViewController.h"
#import "JJFabulousVC.h"
#import "JJChatViewController.h"
#import "JJMessageCommentVC.h"
#import "JJMessageCell.h"
#import "JJMessageModel.h"
#import "JJMessageDataTool.h"

//消息界面
@interface JJMessageViewController () <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray <JJMessageModel *>*messageArray;
@property (nonatomic, copy) NSString *conversationId;
@property (nonatomic,strong) NSMutableArray *conversationIdArrM;
@property (nonatomic, strong) NSMutableArray *sessionArray;

@end

@implementation JJMessageViewController

static NSString *JJMessgaeCellID = @"JJMessgaeCellID";

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSArray *array = @[@{@"uname":@"評(píng)論我的", @"imgPath":@"personCenter_comment"},
                       @{@"uname":@"贊我的", @"imgPath":@"personCenter_admire"},
                       @{@"uname":@"客服", @"imgPath":@"personCenter_kefu"},
                       ];
    if (![[JJMessageDataTool shareMessageTool] getLoginStatus]) {
        [[JJMessageDataTool shareMessageTool] loginEMClient];
    }
    self.messageArray = [NSMutableArray array];
    self.conversationIdArrM = [NSMutableArray array];
    
    for (NSDictionary *dic in array) {
        JJMessageModel *model = [JJMessageModel modelWithDictionary:dic];
        [self.messageArray addObject:model];
    }
    
    self.tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
    [self.view addSubview:self.tableView];
    [self.tableView registerClass:[JJMessageCell class] forCellReuseIdentifier:JJMessgaeCellID];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.tableFooterView = [[UIView alloc] init];
    
    [self getAllSessions];
    
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Object Private Function

- (void)loadMessageDataWithArr:(NSArray *)messageArr
{
    if (messageArr.count > 0) {
        
        for (EMMessage *message in messageArr) {
            
            JJMessageModel *model = [[JJMessageModel alloc] init];
            model.uname = [JJConfig getOwnNicename];
            
            self.conversationId = message.conversationId;
            [self.messageArray addObject:model];
        }
        [self.tableView reloadData];
    }
}

#pragma mark - Action && Notification

- (void)didReceivedMessages:(NSNotification *)noti
{
    NSDictionary *messageDict = noti.userInfo;    
    NSArray *messageArr = [messageDict objectForKey:@"receivedMessage"];
    
    if (messageArr.count > 0) {
        
        for (EMMessage *message in messageArr) {
            
            JJMessageModel *model = [[JJMessageModel alloc] init];
            self.conversationId = message.conversationId;
            [self.conversationIdArrM addObject:self.conversationId];
            [self.messageArray addObject:model];
        }
        [self.tableView reloadData];
    }
}

#pragma mark - UITableViewDelegate, UITableViewDataSource

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JJMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:JJMessgaeCellID forIndexPath:indexPath];
    cell.indexPath = indexPath;
    cell.model = self.messageArray[indexPath.row];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    switch (indexPath.row) {
        case 0:
        {
            NSLog(@"跳轉(zhuǎn)評(píng)論頁(yè)");
            JJMessageCommentVC *commentVC = [[JJMessageCommentVC alloc] init];
            [self.navigationController pushViewController:commentVC animated:YES];
        }
            break;
            
        case 1:
        {
            NSLog(@"跳轉(zhuǎn)贊我的頁(yè)");
            JJFabulousVC *nextVC = [[JJFabulousVC alloc] init];
            nextVC.title = @"贊";
            [self.navigationController pushViewController:nextVC animated:YES];
        }
            break;
            
        case 2:
        {
            NSLog(@"跳轉(zhuǎn)客服頁(yè)");
        }
            break;
            
        default:
        {
            NSLog(@"跳轉(zhuǎn)聊天頁(yè)");
            JJChatViewController *nextVC = [[JJChatViewController alloc] init];
            nextVC.messageModel = self.messageArray[indexPath.row];
            nextVC.conversationId = self.messageArray[indexPath.row].conversationId;
            nextVC.title = [nextVC.messageModel.uname isEqualToString:[JJConfig getOwnNicename]]?nextVC.messageModel.toUserName:nextVC.messageModel.uname;
            [self.navigationController pushViewController:nextVC animated:YES];
        }
        break;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 70;
}

-(void)getAllSessions
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
        _sessionArray = (NSMutableArray*)conversations;
        dispatch_async(dispatch_get_main_queue(), ^{
            if(_sessionArray.count){
                for (EMConversation *conversation in _sessionArray) {
//                    [[EMClient sharedClient].chatManager deleteConversation:conversation.conversationId isDeleteMessages:YES completion:nil];
                    JJMessageModel *messageModel = [JJMessageModel modelWithDictionary:conversation.latestMessage.ext];
                    messageModel.conversationId = conversation.conversationId;
                    if (conversation.latestMessage.body.type == EMMessageBodyTypeText) {
                        EMTextMessageBody *textBody = (EMTextMessageBody *)conversation.latestMessage.body;
                        NSNumber *type = [conversation.latestMessage.ext valueForKey:@"type"];
                        if (type.integerValue == 0) {
                            messageModel.lastMessage = textBody.text;
                        } else if (type.integerValue == 2) {
                            messageModel.lastMessage = @"[收到一個(gè)節(jié)目]";
                        } else if (type.integerValue == 1) {
                            messageModel.lastMessage = @"[收到一個(gè)短視頻]";
                        }
                    } else {
                        messageModel.lastMessage = @"[收到一張圖片]";
                    }
                    [self.messageArray addObject:messageModel];
                }
            }
            [self.tableView reloadData];
        });
    });
}

@end

后記

未完蜀铲,待續(xù)~~~

以后這就是我的
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末边琉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子记劝,更是在濱河造成了極大的恐慌变姨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厌丑,死亡現(xiàn)場(chǎng)離奇詭異定欧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怒竿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門砍鸠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人耕驰,你說(shuō)我怎么就攤上這事爷辱。” “怎么了朦肘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵饭弓,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我媒抠,道長(zhǎng)弟断,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任领舰,我火速辦了婚禮夫嗓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冲秽。我一直安慰自己舍咖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布锉桑。 她就那樣靜靜地躺著排霉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪民轴。 梳的紋絲不亂的頭發(fā)上攻柠,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音后裸,去河邊找鬼瑰钮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛微驶,可吹牛的內(nèi)容都是我干的浪谴。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼因苹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼苟耻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起扶檐,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凶杖,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后款筑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體智蝠,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年奈梳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寻咒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颈嚼,死狀恐怖毛秘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阻课,我是刑警寧澤叫挟,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站限煞,受9級(jí)特大地震影響抹恳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜署驻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一奋献、第九天 我趴在偏房一處隱蔽的房頂上張望健霹。 院中可真熱鬧,春花似錦瓶蚂、人聲如沸糖埋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞳别。三九已至,卻和暖如春杭攻,著一層夾襖步出監(jiān)牢的瞬間祟敛,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工兆解, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留馆铁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓锅睛,卻偏偏與公主長(zhǎng)得像叼架,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子衣撬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 版本記錄 前言 很多app種都集成環(huán)信做第三方信息通訊工具乖订,這里我們就看一下環(huán)信的主要功能和集成方法。先給出環(huán)信3...
    刀客傳奇閱讀 821評(píng)論 2 2
  • 點(diǎn)擊查看原文 Web SDK 開(kāi)發(fā)手冊(cè) SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個(gè)完善的 IM 系統(tǒng)...
    layjoy閱讀 13,674評(píng)論 0 15
  • 1)項(xiàng)目里面不需要環(huán)信SDK的太多功能具练,只是想要聊天和好友功能乍构,其他都不用,那SDK一定要總是跟著更新么扛点? a.環(huán)...
    DefaultYuan閱讀 26,540評(píng)論 17 59
  • 唯一能選的時(shí)間是判斷低估哥遮,高估。然后就隨便買陵究,或隨便賣
    新興市場(chǎng)的小邏輯閱讀 79評(píng)論 0 0
  • 打霜了眠饮,工地也放假了,給人裝修的新房也完工了铜邮。 今天咱從米倉(cāng)山深處仪召,翻兩座大山口回鎮(zhèn)巴縣城。 鎮(zhèn)巴古稱定遠(yuǎn)松蒜,又叫班...
    歪才大白話閱讀 250評(píng)論 2 11