李洪强iOS开发之-环信05_EaseUI 使用指南
李洪强iOS开发之-环信05_EaseUI 使用指南
EaseUI 使用指南
简介
快速集成
初始化
第 1 步:引入相关头文件 #import “EaseUI.h”。
第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- [[EaseSDKHelper shareHelper] easemobApplication:application
- didFinishLaunchingWithOptions:launchOptions
- appkey:@"douser#istore"
- apnsCertName:@"istore_dev"
- otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];
- return YES;
- }
聊天会话
创建聊天会话、传递用户或群 ID 和会话类型(EMConversationType)。
- EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"8001" conversationType:EMConversationTypeChat];
聊天会话功能扩展
EaseUI 提供现成的聊天会话 ViewController,可以通过继承 EaseMessageViewController 方式(参考 ChatDemo-UI3.0 中 ChatViewController)实现对聊天会话的扩展。
也可以直接使用 EaseMessageViewController,通过 EaseMessageViewControllerDelegate 和 EaseMessageViewControllerDataSource 两个协议实现对 EaseMessageViewController 的扩展。
实现自定义聊天样式
EaseMessageViewControllerDelegate
获取自定义消息 cell,根据 messageModel,用户自己判断是否显示自定义消息 cell。如果返回 nil 会显示默认;如果返回 cell 会显示用户自定义消息cell。
- /*!
- @method
- @brief 获取消息自定义cell
- @discussion 用户根据messageModel判断是否显示自定义cell。返回nil显示默认cell,否则显示用户自定义cell
- @param tableView 当前消息视图的tableView
- @param messageModel 消息模型
- @result 返回用户自定义cell
- */
- - (UITableViewCell *)messageViewController:(UITableView *)tableView
- cellForMessageModel:(id<IMessageModel>)messageModel;
- /*!
- @method
- @brief 获取消息cell高度
- @discussion 用户根据messageModel判断,是否自定义显示cell的高度
- @param viewController 当前消息视图
- @param messageModel 消息模型
- @param cellWidth 视图宽度
- @result 返回用户自定义cell
- */
- - (CGFloat)messageViewController:(EaseMessageViewController *)viewController
- heightForMessageModel:(id<IMessageModel>)messageModel
- withCellWidth:(CGFloat)cellWidth;
- //具体创建自定义Cell的样例:
- - (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model
- {
- //样例为如果消息是文本消息显示用户自定义cell
- if (model.bodyType == eMessageBodyType_Text) {
- NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
- //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
- CustomMessageCell *cell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
- cell.selectionStyle = UITableViewCellSelectionStyleNone;
- }
- cell.model = model;
- return cell;
- }
- return nil;
- }
- - (CGFloat)messageViewController:(EaseMessageViewController *)viewController
- heightForMessageModel:(id<IMessageModel>)messageModel
- withCellWidth:(CGFloat)cellWidth
- {
- //样例为如果消息是文本消息使用用户自定义cell的高度
- if (messageModel.bodyType == EMMessageBodyTypeText) {
- //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
- return [CustomMessageCell cellHeightWithModel:messageModel];
- }
- return 0.f;
- }
通过自定义cell展示动态表情的效果图:
选中消息的回调
- /*!
- @method
- @brief 选中消息的回调
- @discussion 用户根据messageModel判断,是否自定义处理消息选中时间。返回YES为自定义处理,返回NO为默认处理
- @param viewController 当前消息视图
- @param messageModel 消息模型
- @result 是否采用自定义处理
- */
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- didSelectMessageModel:(id<IMessageModel>)messageModel;
- //选中消息回调的样例:
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- didSelectMessageModel:(id<IMessageModel>)messageModel
- {
- BOOL flag = NO;
- //样例为如果消息是文件消息用户自定义处理选中逻辑
- switch (messageModel.bodyType) {
- case EMMessageBodyTypeImage:
- case EMMessageBodyTypeLocation:
- case EMMessageBodyTypeVideo:
- case EMMessageBodyTypeVoice:
- break;
- case EMMessageBodyTypeFile:
- {
- flag = YES;
- NSLog(@"用户自定义实现");
- }
- break;
- default:
- break;
- }
- return flag;
- }
用户选中头像的回调
- /*!
- @method
- @brief 点击消息头像
- @discussion 获取用户点击头像回调
- @param viewController 当前消息视图
- @param messageModel 消息模型
- @result
- */
- - (void)messageViewController:(EaseMessageViewController *)viewController
- didSelectAvatarMessageModel:(id<IMessageModel>)messageModel;
- //获取用户点击头像回调的样例:
- - (void)messageViewController:(EaseMessageViewController *)viewController
- didSelectAvatarMessageModel:(id<IMessageModel>)messageModel
- {
- //UserProfileViewController用户自定义的个人信息视图
- //样例的逻辑是选中消息头像后,进入该消息发送者的个人信息
- UserProfileViewController *userprofile = [[UserProfileViewController alloc] initWithUsername:messageModel.message.from];
- [self.navigationController pushViewController:userprofile animated:YES];
- }
录音按钮状态的回调
- /*!
- @method
- @brief 底部录音功能按钮状态回调
- @discussion 获取底部录音功能按钮状态回调,根据EaseRecordViewType,用户自定义处理UI的逻辑
- @param viewController 当前消息视图
- @param recordView 录音视图
- @param type 录音按钮当前状态
- @result
- */
- - (void)messageViewController:(EaseMessageViewController *)viewController
- didSelectRecordView:(UIView *)recordView
- withEvenType:(EaseRecordViewType)type;
- //录音按钮状态的回调样例:
- - (void)messageViewController:(EaseMessageViewController *)viewController
- didSelectRecordView:(UIView *)recordView
- withEvenType:(EaseRecordViewType)type
- {
- /*
- EaseRecordViewTypeTouchDown,//录音按钮按下
- EaseRecordViewTypeTouchUpInside,//手指在录音按钮内部时离开
- EaseRecordViewTypeTouchUpOutside,//手指在录音按钮外部时离开
- EaseRecordViewTypeDragInside,//手指移动到录音按钮内部
- EaseRecordViewTypeDragOutside,//手指移动到录音按钮外部
- */
- //根据type类型,用户自定义处理UI的逻辑
- switch (type) {
- case EaseRecordViewTypeTouchDown:
- {
- if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
- [(EaseRecordView *)self.recordView recordButtonTouchDown];
- }
- }
- break;
- case EaseRecordViewTypeTouchUpInside:
- {
- if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
- [(EaseRecordView *)self.recordView recordButtonTouchUpInside];
- }
- [self.recordView removeFromSuperview];
- }
- break;
- case EaseRecordViewTypeTouchUpOutside:
- {
- if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
- [(EaseRecordView *)self.recordView recordButtonTouchUpOutside];
- }
- [self.recordView removeFromSuperview];
- }
- break;
- case EaseRecordViewTypeDragInside:
- {
- if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
- [(EaseRecordView *)self.recordView recordButtonDragInside];
- }
- }
- break;
- case EaseRecordViewTypeDragOutside:
- {
- if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
- [(EaseRecordView *)self.recordView recordButtonDragOutside];
- }
- }
- break;
- default:
- break;
- }
- }
EaseMessageViewControllerDataSource
用户判断消息是否允许长按,返回布尔值;如果用户允许长按,此方法为通知用户触发长按手势,返回布尔值,如果返回 NO 默认方式处理,返回 YES 采用用户自定义的处理方式。
- /*!
- @method
- @brief 是否允许长按
- @discussion 获取是否允许长按的回调,默认是NO
- @param viewController 当前消息视图
- @param indexPath 长按消息对应的indexPath
- @result
- */
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- canLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
- /*!
- @method
- @brief 触发长按手势
- @discussion 获取触发长按手势的回调,默认是NO
- @param viewController 当前消息视图
- @param indexPath 长按消息对应的indexPath
- @result
- */
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- didLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
- //长按收拾回调样例:
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- canLongPressRowAtIndexPath:(NSIndexPath *)indexPath
- {
- //样例给出的逻辑是所有cell都允许长按
- return YES;
- }
- - (BOOL)messageViewController:(EaseMessageViewController *)viewController
- didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
- {
- //样例给出的逻辑是长按cell之后显示menu视图
- id object = [self.dataArray objectAtIndex:indexPath.row];
- if (![object isKindOfClass:[NSString class]]) {
- EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
- [cell becomeFirstResponder];
- self.menuIndexPath = indexPath;
- [self _showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
- }
- return YES;
- }
Demo3.0实现的消息长按效果演示:
将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像。
- /*!
- @method
- @brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
- @discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
- @param viewController 当前消息视图
- @param EMMessage 聊天消息对象类型
- @result 返回<IMessageModel>协议的类型
- */
- - (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
- modelForMessage:(EMMessage *)message;
- //具体样例:
- - (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
- modelForMessage:(EMMessage *)message
- {
- //用户可以根据自己的用户体系,根据message设置用户昵称和头像
- id<IMessageModel> model = nil;
- model = [[EaseMessageModel alloc] initWithMessage:message];
- model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
- model.avatarURLPath = @"";//头像网络地址
- model.nickname = @"昵称";//用户昵称
- return model;
- }
聊天会话页面头像和昵称的效果演示:
聊天会话样式自定义
聊天样式的自定义需要在 EaseMessageViewController 中 viewDidload 结束前设置。
- //@property中带有UI_APPEARANCE_SELECTOR,都可以通过set的形式设置样式,具体可以参考EaseBaseMessageCell.h,EaseMessageCell.h
- [[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage imageNamed:@"chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];//设置发送气泡
- [[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];//设置接收气泡
- [[EaseBaseMessageCell appearance] setAvatarSize:40.f];//设置头像大小
- [[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f];//设置头像圆角
消息发送
EaseSDKHelper 封装了发送消息的方法。
具体发送消息样例:
- /*
- EMChatTypeChat 单聊消息
- EMChatTypeGroupChat 群聊消息
- EMChatTypeChatRoom 聊天室消息
- */
- //发送文字消息
- EMMessage *message = [EaseSDKHelper sendTextMessage:@"要发送的消息"
- to:@"6001"//接收方
- messageType:EMChatTypeChat//消息类型
- messageExt:nil]; //扩展信息
- //发送位置消息
- EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:35.1//经度
- longitude:35.1//纬度
- address:"地址"
- to:@"6001"//接收方
- messageType:EMChatTypeChat//消息类型
- messageExt:nil];//扩展信息
- //发送图片消息
- EMMessage *message = [EaseSDKHelper sendImageMessageWithImageData:imageData//发送的图片数据NSData
- to:@"6001"//接收方
- messageType:EMChatTypeChat//消息类型
- messageExt:nil];//扩展信息
- //发送音频消息
- EMMessage *message = [EaseSDKHelper sendVoiceMessageWithLocalPath:localPath//音频本地地址
- duration:duration//语音的时长,单位是秒
- to:@"6001"//接收方
- messageType:EMChatTypeChat//消息类型
- messageExt:nil];//扩展信息
- //发送视频文件消息
- EMMessage *message = [EaseSDKHelper sendVideoMessageWithURL:url//发送的视频地址
- to:@"6001"//接收方
- messageType:EMChatTypeChat//消息类型
- messageExt:nil];//扩展信息
- //发送构造成功的消息
- [[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {
- }];
会话列表
会话列表初始化
- EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] init];
会话列表扩展
EaseConversationListViewControllerDataSource
用户根据 conversationModel 实现,实现自定义会话中最后一条消息文案的显示内容。
- /*!
- @method
- @brief 获取最后一条消息显示的内容
- @discussion 用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容
- @param conversationListViewController 当前会话列表视图
- @param IConversationModel 会话模型
- @result 返回用户最后一条消息显示的内容
- */
- - (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel;
- /*!
- @method
- @brief 获取最后一条消息显示的时间
- @discussion 用户可以根据conversationModel,自定义实现会话列表中时间文案的显示内容
- @param conversationListViewController 当前会话列表视图
- @param IConversationModel 会话模型
- @result 返回用户最后一条消息时间的显示文案
- */
- - (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel;
- //最后一条消息展示内容样例
- - (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel
- {
- NSString *latestMessageTitle = @"";
- EMMessage *lastMessage = [conversationModel.conversation latestMessage];
- if (lastMessage) {
- EMMessageBody *messageBody = lastMessage.body;
- switch (messageBody.type) {
- case EMMessageBodyTypeImage:{
- latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
- } break;
- case EMMessageBodyTypeText:{
- // 表情映射。
- NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
- convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
- latestMessageTitle = didReceiveText;
- if ([lastMessage.ext objectForKey:MESSAGE_ATTR_IS_BIG_EXPRESSION]) {
- latestMessageTitle = @"[动画表情]";
- }
- } break;
- case EMMessageBodyTypeVoice:{
- latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
- } break;
- case EMMessageBodyTypeLocation: {
- latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
- } break;
- case EMMessageBodyTypeVideo: {
- latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
- } break;
- case EMMessageBodyTypeFile: {
- latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
- } break;
- default: {
- } break;
- }
- }
- return latestMessageTitle;
- }
- //最后一条消息展示时间样例
- - (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel
- {
- NSString *latestMessageTime = @"";
- EMMessage *lastMessage = [conversationModel.conversation latestMessage];;
- if (lastMessage) {
- latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
- }
- return latestMessageTime;
- }
会话列表最后一条消息和时间显示的效果演示:
EaseConversationListViewControllerDelegate
点击会话列表用户可以根据 conversationModel 自定义处理逻辑。
- /*!
- @method
- @brief 获取点击会话列表的回调
- @discussion 获取点击会话列表的回调后,点击会话列表用户可以根据conversationModel自定义处理逻辑
- @param conversationListViewController 当前会话列表视图
- @param IConversationModel 会话模型
- @result
- */
- - (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- didSelectConversationModel:(id<IConversationModel>)conversationModel;
- //会话列表点击的回调样例
- - (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
- didSelectConversationModel:(id<IConversationModel>)conversationModel
- {
- //样例展示为根据conversationModel,进入不同的会话ViewController
- if (conversationModel) {
- EMConversation *conversation = conversationModel.conversation;
- if (conversation) {
- if ([[RobotManager sharedInstance] isRobotWithUsername:conversation.conversationId]) {
- RobotChatViewController *chatController = [[RobotChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
- chatController.title = [[RobotManager sharedInstance] getRobotNickWithUsername:conversation.conversationId];
- [self.navigationController pushViewController:chatController animated:YES];
- } else {
- ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
- chatController.title = conversationModel.title;
- [self.navigationController pushViewController:chatController animated:YES];
- }
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"setupUnreadMessageCount" object:nil];
- [self.tableView reloadData];
- }
- }
联系人列表
联系人列表初始化
- EaseUsersListViewController *listViewController = [[EaseUsersListViewController alloc] init];
联系人列表扩展
需要实现 EMUserListViewControllerDataSource。
根据 buddy 获取用户自定信息,联系人列表里展示昵称和头像。
- /*!
- @method
- @brief 获取用户模型
- @discussion 根据buddy获取用户自定信息,联系人列表里展示昵称和头像
- @param userListViewController 当前联系人视图
- @param buddy 好友的信息描述类
- @result 返回用户模型
- */
- - (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
- modelForBuddy:(NSString *)buddy;
- //联系人列表扩展样例
- - (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
- modelForBuddy:(NSString *)buddy
- {
- //用户可以根据自己的用户体系,根据buddy设置用户昵称和头像
- id<IUserModel> model = nil;
- model = [[EaseUserModel alloc] initWithBuddy:buddy];
- model.avatarURLPath = @"";//头像网络地址
- model.nickname = @"昵称";//用户昵称
- return model;
- }
联系人列表头像和昵称的效果演示:
李洪强iOS开发之-环信05_EaseUI 使用指南的更多相关文章
- 李洪强iOS开发之-环信04_消息
李洪强iOS开发之-环信04_消息 消息:IM 交互实体,在 SDK 中对应的类型是 EMMessage.EMMessage 由 EMMessageBody 组成. 构造消息 构造文字消息 EMT ...
- 李洪强iOS开发之-环信03_集成 SDK 基础功能
李洪强iOS开发之-环信03_集成 SDK 基础功能 集成 SDK 基础功能 在您阅读此文档时,我们假定您已经具备了基础的 iOS 应用开发经验,并能够理解相关基础概念. SDK 同步/异步方法区分 ...
- 李洪强iOS开发之-环信02.2_环信官网下载环信 SDK
李洪强iOS开发之-环信02.2_环信官网下载环信 SDK 移动客服即时通讯云 iOS SDK 当前版本:V3.1.4 2016-07-08 [ 版本历史 ] | 开发指南 | 知识库 | Demo源 ...
- 李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档
李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档 SDK 2.x 至 3.0 升级指南 环信 SDK 3.0 升级文档 3.0 中的核心类为 EMClient 类,通过 EMCl ...
- 李洪强iOS开发之-环信02_iOS SDK 介绍及导入
李洪强iOS开发之-环信02_iOS SDK 介绍及导入 iOS SDK 介绍及导入 iOS SDK 介绍 环信 SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架.包括以下几个部分: SD ...
- 李洪强iOS开发之-环信01_iOS SDK 前的准备工作
李洪强iOS开发之-环信01_iOS SDK 前的准备工作 1.1_注册环信开发者账号并创建后台应用 详细步骤: 注册并创建应用 注册环信开发者账号 第 1 步:在环信官网上点击“即时通讯云”,并点 ...
- 李洪强iOS开发之-环信02.3_具体接口讲解 - Apple Docs
http://www.easemob.com/apidoc/ios/chat3.0/annotated.html Apple Docs.
- 李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入
李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入 01 - 直接在项目中导入SDK和一些静态库 这个时候,没有错误的编译没有错误的话,就说明SDK已经配置成功 还有一种方法是用cocoap ...
- 李洪强iOS开发本人集成环信的经验总结_03_注册
李洪强iOS开发本人集成环信的经验总结_03_注册 环信一共提供了三种注册的方法: 01 同步注册: 02 异步注册: 03 - 使用代理回调进行注册,但是3.0没有了,3.0之前有 调用注册 ...
随机推荐
- Oracle12c创建新用户提示公共用户名或角色无效
今天将备份的数据库还原到一台新的电脑上,首先要创建用户,执行如下语句: create user fxhy identified " default tablespace USERS temp ...
- HW--字符串加解密
package t0817; import java.util.Scanner; public class StringEncrypt { public static void main(String ...
- <转载>国外程序员推荐的免费编程书籍资源
一.George Stocker 提供了一大串,分类如下: How to Design Programs: An Introduction to Computing and Programming 2 ...
- asp.net连接mysql数据库
方法一:使用MySQL推出的MySQL Connector/Net组件, 该组件是MySQL为ADO.NET访问MySQL数据库设计的.NET专用访问组件.完成该组件后,需要在项目中引用这个组件,也可 ...
- DIV+CSS相对IE8的兼容问题
CSS技巧: 1.div的垂直居中问题 vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字,就垂直居中了.缺点是要控制内容 ...
- WPF 中,动态创建Button,并使Button得样式按照自定义的Resource样式显示
第一步:自定义一个Button的样式 1.新建一个xaml文件,在其中自定义好自己的Resources 这个Resource 的根节点是 <ResourceDictionary xmlns=&q ...
- C++ IO 详细用法
http://www.cnblogs.com/keam37/ keam所有 转载请注明出处 本文将分别从<iostream>,<sstream>,<fstream> ...
- 【nodemailer】之 work with mustache
之前对nodemailer做了简要的研究,基本上是搞定了发邮件的问题.但很多情况下邮件的内容不是固定的,然后又需要有一个合适的样式,这就需要使用模板了.nodemailer有nodemailer-ma ...
- C++学习 (转)
1.把C++当成一门新的语言学习: 2.看<Thinking In C++>: 3.看<The C++ Programming Language>和<Inside The ...
- ACE_linux:读写锁
1.涉及类 ACE_RW_Thread_Mutex //ACE读写锁ACE_Read_Guard //ACE加读锁ACE_Write_Guard //ACE加写锁ACE_Thread_Manager ...