1.聊天机器人的模型创建
1、plist文件message.plist
2、创建Message聊天内容的模型FRMessage
FRMessage.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//message消息模型
typedef enum{
FRMessageMe=0,//表示自己
FRMessageOther=1//表示对方
} FRMessageType;
@interface FRMessage : NSObject
@property(nonatomic,copy)NSString* text;
@property(nonatomic,copy)NSString* time;
@property(nonatomic,assign)FRMessageType type;
-(instancetype)initWithDictionary:(NSDictionary*) dict;
+(instancetype)messageWithDictionary:(NSDictionary*) dict;
@end
NS_ASSUME_NONNULL_END
FRMessage.m
#import "FRMessage.h"
@implementation FRMessage
-(instancetype)initWithDictionary:(NSDictionary*) dict{
if (self=[super init]) {
//从字典中给模型各属性赋值
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+(instancetype)messageWithDictionary:(NSDictionary*) dict{
return [[self alloc]initWithDictionary:dict];
}
@end
2、创建MessageFrame模型FRMessageFrame
FRMessageFrame.h
#import <Foundation/Foundation.h>
#import "FRMessage.h"
#import <CoreGraphics/CoreGraphics.h>
NS_ASSUME_NONNULL_BEGIN
@interface FRMessageFrame : NSObject
//数据模型
@property(nonatomic,strong)FRMessage* message;
//时间label,内容和头像的frame
@property(nonatomic,assign,readonly)CGRect timeFrame;
@property(nonatomic,assign,readonly)CGRect iconFrame;
@property(nonatomic,assign,readonly)CGRect textFrame;
@property(nonatomic,assign,readonly)CGFloat rowHeight;
@end
NS_ASSUME_NONNULL_END
FRMessageFrame.m
#import "FRMessageFrame.h"
@implementation FRMessageFrame
//重写message的set方法
-(void)setMessage:(FRMessage *)message{
_message=message;
//计算每个控件的frame和行高
//self.iconFrame=
}
@end
3、常见tableview的单元格类FRMessageCell类
FRMessageCell.h
#import <UIKit/UIKit.h>
#import "FRMessageFrame.h"
NS_ASSUME_NONNULL_BEGIN
@interface FRMessageCell : UITableViewCell
//为单元格增加一个frame模型属性
@property(nonatomic,strong) FRMessageFrame* messageFrame;
//封装一个创建自定义单元格的类方法
+(instancetype)messageCellWithTableview:(UITableView*)tableView;
@end
NS_ASSUME_NONNULL_END
FRMessageCell.m
#import "FRMessageCell.h"
#import "FRMessage.h"
@interface FRMessageCell()
@property(nonatomic,weak)UILabel* lblTime;
@property(nonatomic,weak)UIImageView* imgViewIcon;
@property(nonatomic,weak)UIButton* btnText;
@end
@implementation FRMessageCell
//重写initWithStyle方法
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self=[super initWithStyle:style reuseIdentifier:reuseIdentifier]) {//如果可以调用父类的初始化方法
//创建子控件
//显示时间的label
UILabel* lblTime=[[UILabel alloc]init];
self.lblTime=lblTime;
//contentView是默认的单元格的内容
[self.contentView addSubview:lblTime];
//显示头像的imageview
UIImageView* imgViewIcon=[[UIImageView alloc]init];
self.imgViewIcon=imgViewIcon;
[self.contentView addSubview:imgViewIcon];
//显示正文的按钮
UIButton* btnText=[[UIButton alloc]init];
self.btnText=btnText;
[self.contentView addSubview:btnText];
}
return self;
}
//重写messageFrame属性的set方法
-(void)setMessageFrame:(FRMessageFrame *)messageFrame{
_messageFrame=messageFrame;
//获取数据模型
FRMessage* messageModel=messageFrame.message;
//分别设置每个子控件的数据和frame
//设置时间label的数据和frame
self.lblTime.text=messageModel.time;
self.lblTime.frame=messageFrame.timeFrame;
//设置头像imgIcon的数据和frame
//根据消息类型判断使用那张图片
NSString* iconImg=messageModel.type==FRMessageMe?@"me":@"other";
self.imgViewIcon.image=[UIImage imageNamed:iconImg];
self.imgViewIcon.frame=messageFrame.iconFrame;
//设置正文text的数据和frame
[self.btnText setTitle:messageModel.text forState:UIControlStateNormal];
self.btnText.frame=messageFrame.textFrame;
}
//封装一个创建自定义单元格的类方法
+(instancetype)messageCellWithTableview:(UITableView*)tableView{
//创建单元格
static NSString* strID=@"mycellId";
FRMessageCell* cell= [tableView dequeueReusableCellWithIdentifier:strID];
if (cell==nil) {
cell=[[FRMessageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strID];
}
return cell;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
4、控制器ViewController
#import "ViewController.h"
#import "FRMessage.h"
#import "FRMessageFrame.h"
#import "FRMessageCell.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
//用来保存所有消息的frame模型对象的数组
@property(nonatomic,strong)NSMutableArray* messageFrames;
@end
@implementation ViewController
#pragma mark - /***懒加载数据**/
//懒加载数据
//重写messageFrames的get方法
-(NSMutableArray*)messageFrames{
if (_messageFrames==nil) {
//plist文件的路径
NSString* path=[[NSBundle mainBundle]pathForResource:@"messages.plist" ofType:nil];
//通过路径拿到所有字典
NSArray* arrayDict=[NSArray arrayWithContentsOfFile:path];
//遍历字典并添加到一个动态模型数组中
NSMutableArray* messageModelsM=[NSMutableArray array];
for (NSDictionary* dict in arrayDict) {
//创建数据模型
FRMessage* messageModel=[FRMessage messageWithDictionary:dict];
//创建一个Frame模型
FRMessageFrame* messageFrameModel=[[FRMessageFrame alloc]init];
messageFrameModel.message=messageModel;
[messageModelsM addObject:messageFrameModel];
}
_messageFrames=messageModelsM;
}
return _messageFrames;
}
//实现数据源方法
//返回分组数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
//返回分行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.messageFrames.count;
}
//返回单元格
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//获取模型数据
FRMessageFrame* messageFrameModel=self.messageFrames[indexPath.row];
//创建单元格
FRMessageCell* cell=[FRMessageCell messageCellWithTableview:tableView];
//给模型对象设置数据
cell.messageFrame=messageFrameModel;
//返回cell
return cell;
}
//返回每一行行高的方法
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
FRMessageFrame* messageFrame=self.messageFrames[indexPath.row];
return messageFrame.rowHeight;
}
- (void)viewDidLoad {
[super viewDidLoad];
//FRMessageFrame* messageFrame=[[FRMessageFrame alloc]init];
//NSLog(@"%ld",self.messageFrames.count);
}
@end
2.聊天机器人UI部分完整版
1、数据模型FRMessage
FRMessage.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//message消息模型
typedef enum{
FRMessageMe=0,//表示自己
FRMessageOther=1//表示对方
} FRMessageType;
@interface FRMessage : NSObject
@property(nonatomic,copy)NSString* text;
@property(nonatomic,copy)NSString* time;
@property(nonatomic,assign)FRMessageType type;
//添加一个时间是否一致的标志属性,用以是否显示时间label
@property(nonatomic,assign) BOOL hideTime;
-(instancetype)initWithDictionary:(NSDictionary*) dict;
+(instancetype)messageWithDictionary:(NSDictionary*) dict;
@end
NS_ASSUME_NONNULL_END
FRMessage.m
#import "FRMessage.h"
@implementation FRMessage
-(instancetype)initWithDictionary:(NSDictionary*) dict{
if (self=[super init]) {
//从字典中给模型各属性赋值
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+(instancetype)messageWithDictionary:(NSDictionary*) dict{
return [[self alloc]initWithDictionary:dict];
}
@end
2、数据模型FRMessageFrame
FRMessageFrame.h
#import <Foundation/Foundation.h>
#import "FRMessage.h"
#import <CoreGraphics/CoreGraphics.h>
#define textFont [UIFont systemFontOfSize:13]
NS_ASSUME_NONNULL_BEGIN
@interface FRMessageFrame : NSObject
//数据模型
@property(nonatomic,strong)FRMessage* message;
//时间label,内容和头像的frame
@property(nonatomic,assign,readonly)CGRect timeFrame;
@property(nonatomic,assign,readonly)CGRect iconFrame;
@property(nonatomic,assign,readonly)CGRect textFrame;
@property(nonatomic,assign,readonly)CGFloat rowHeight;
@end
NS_ASSUME_NONNULL_END
FRMessageFrame.m
#import "FRMessageFrame.h"
#import <UIKit/UIKit.h>
#import "NSString+FRNSStringExt.h"
@implementation FRMessageFrame
//重写message的set方法
-(void)setMessage:(FRMessage *)message{
_message=message;
//计算每个控件的frame和行高
//获取屏幕宽度
CGFloat screenW=[UIScreen mainScreen].bounds.size.width;
CGFloat margin=10;
//计算时间的frame
CGFloat timeX=0;
CGFloat timeY=0;
CGFloat timeW=screenW;
CGFloat timeH=18;
//设置时间label的显示,由于对话时间接近,时间label有可能被隐藏
if (!message.hideTime) {
//如果需要显示时间label,那么再计算时间label的frame
_timeFrame=CGRectMake(timeX, timeY, timeW, timeH);
}
//计算头像的frame
CGFloat iconW=30;
CGFloat iconH=30;
CGFloat iconX=message.type==FRMessageOther?margin:(screenW-margin-iconW);
CGFloat iconY=CGRectGetMaxY(_timeFrame)+margin;
_iconFrame=CGRectMake(iconX, iconY, iconW, iconH);
//计算正文的frame
//先计算正文的大小,在计算x,y
CGSize textSize=[message.text sizeOfTextwithMaxSize:CGSizeMake(200, MAXFLOAT) font:textFont];
CGFloat textW=textSize.width+40;//加的新值是因为正文背景不能垫在下方,需要放大按钮
CGFloat textH=textSize.height+30;//加的新值是因为正文背景不能垫在下方,需要放大按钮
CGFloat textY=iconY;
CGFloat textX=message.type==FRMessageOther?CGRectGetMaxX(_iconFrame):(screenW-margin-iconW-textW);
_textFrame=CGRectMake(textX, textY, textW, textH);
//计算行高
//获取头像的最大的Y值和正文的最大的y值,然后用最大y值+margin
CGFloat maxY=MAX(CGRectGetMaxY(_iconFrame), CGRectGetMaxY(_textFrame));
_rowHeight=maxY+margin;
}
@end
3、类扩展NSString+FRNSStringExt,NSString的扩展类
NSString+FRNSStringExt.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (FRNSStringExt)
//对象方法
-(CGSize)sizeOfTextwithMaxSize:(CGSize)maxSize font:(UIFont*)font;
//类方法
+(CGSize)sizeWithText:(NSString*)text maxSzie:(CGSize)maxSize font:(UIFont*)font;
@end
NS_ASSUME_NONNULL_END
NSString+FRNSStringExt.m
#import "NSString+FRNSStringExt.h"
@implementation NSString (FRNSStringExt)
//对象方法
-(CGSize)sizeOfTextwithMaxSize:(CGSize)maxSize font:(UIFont*)font{
NSDictionary* attrs=@{NSFontAttributeName:font};
return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}
//类方法
+(CGSize)sizeWithText:(NSString*)text maxSzie:(CGSize)maxSize font:(UIFont*)font{
return [text sizeOfTextwithMaxSize:maxSize font:font];
}
@end
4、单元格类FRMessageCell
FRMessageCell.h
#import <UIKit/UIKit.h>
#import "FRMessageFrame.h"
NS_ASSUME_NONNULL_BEGIN
@interface FRMessageCell : UITableViewCell
//为单元格增加一个frame模型属性
@property(nonatomic,strong) FRMessageFrame* messageFrame;
//封装一个创建自定义单元格的类方法
+(instancetype)messageCellWithTableview:(UITableView*)tableView;
@end
NS_ASSUME_NONNULL_END
FRMessageCell.m
#import "FRMessageCell.h"
#import "FRMessage.h"
@interface FRMessageCell()
@property(nonatomic,weak)UILabel* lblTime;
@property(nonatomic,weak)UIImageView* imgViewIcon;
@property(nonatomic,weak)UIButton* btnText;
@end
@implementation FRMessageCell
//重写initWithStyle方法
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self=[super initWithStyle:style reuseIdentifier:reuseIdentifier]) {//如果可以调用父类的初始化方法
//创建子控件
//显示时间的label
UILabel* lblTime=[[UILabel alloc]init];
self.lblTime=lblTime;
//设置时间label的文字字体及文字居中
lblTime.font=[UIFont systemFontOfSize:12];
lblTime.textAlignment=NSTextAlignmentCenter;
//contentView是默认的单元格的内容
[self.contentView addSubview:lblTime];
//显示头像的imageview
UIImageView* imgViewIcon=[[UIImageView alloc]init];
self.imgViewIcon=imgViewIcon;
[self.contentView addSubview:imgViewIcon];
//显示正文的按钮
UIButton* btnText=[[UIButton alloc]init];
//设置正文的字体大小
btnText.titleLabel.font=textFont;
//设置文字正文的颜色及文本换行
[btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnText.titleLabel.numberOfLines=0;
//设置按钮的内边距
btnText.contentEdgeInsets=UIEdgeInsetsMake(15, 20, 15, 20);
self.btnText=btnText;
[self.contentView addSubview:btnText];
}
//设置单元格的背景色
self.backgroundColor=[UIColor clearColor];//取消单元格背景色
return self;
}
//重写messageFrame属性的set方法
-(void)setMessageFrame:(FRMessageFrame *)messageFrame{
_messageFrame=messageFrame;
//获取数据模型
FRMessage* messageModel=messageFrame.message;
//分别设置每个子控件的数据和frame
//设置时间label的数据和frame
self.lblTime.text=messageModel.time;
self.lblTime.frame=messageFrame.timeFrame;
self.lblTime.hidden=messageModel.hideTime;//设置是否隐藏时间label
//设置头像imgIcon的数据和frame
//根据消息类型判断使用那张图片
NSString* iconImg=messageModel.type==FRMessageMe?@"me":@"other";
self.imgViewIcon.image=[UIImage imageNamed:iconImg];
self.imgViewIcon.frame=messageFrame.iconFrame;
//设置正文text的数据和frame
[self.btnText setTitle:messageModel.text forState:UIControlStateNormal];
self.btnText.frame=messageFrame.textFrame;
//设置正文的背景图
NSString* imgNor,*imgHighlighted;
if (messageModel.type) {
//自己发的消息
imgNor=@"chat_recive_nor";
imgHighlighted=@"chat_recive_press_pic";
//设置消息的文字颜色为“黑色”
[self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}else{
//对方发的消息
imgNor=@"chat_send_nor";
imgHighlighted=@"chat_send_press_pic";
//设置消息的文字颜色为“白色”
[self.btnText setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
//加载图片
UIImage* imageNormal=[UIImage imageNamed:imgNor];
UIImage* imageHighlighted=[UIImage imageNamed:imgHighlighted];
//使用9path的方式把背景图拉伸(平铺方式拉伸)
//stretchableImageWithLeftCapWidth和topCapHeight是裁切的交互点,这里分别取去背景图的中间
imageNormal=[imageNormal stretchableImageWithLeftCapWidth:imageNormal.size.width*0.5 topCapHeight:imageNormal.size.height*0.5];
imageHighlighted=[imageHighlighted stretchableImageWithLeftCapWidth:imageHighlighted.size.width*0.5 topCapHeight:imageHighlighted.size.height*0.5];
//设置背景图
[self.btnText setBackgroundImage:imageNormal forState:UIControlStateNormal];
[self.btnText setBackgroundImage:imageHighlighted forState:UIControlStateHighlighted];
}
//封装一个创建自定义单元格的类方法
+(instancetype)messageCellWithTableview:(UITableView*)tableView{
//创建单元格
static NSString* strID=@"mycellId";
FRMessageCell* cell= [tableView dequeueReusableCellWithIdentifier:strID];
if (cell==nil) {
cell=[[FRMessageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strID];
}
return cell;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
5、控制器类ViewController
ViewController.m
#import "ViewController.h"
#import "FRMessage.h"
#import "FRMessageFrame.h"
#import "FRMessageCell.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *txtInput;
//用来保存所有消息的frame模型对象的数组
@property(nonatomic,strong)NSMutableArray* messageFrames;
@end
@implementation ViewController
#pragma mark - /***懒加载数据**/
//懒加载数据
//重写messageFrames的get方法
-(NSMutableArray*)messageFrames{
if (_messageFrames==nil) {
//plist文件的路径
NSString* path=[[NSBundle mainBundle]pathForResource:@"messages.plist" ofType:nil];
//通过路径拿到所有字典
NSArray* arrayDict=[NSArray arrayWithContentsOfFile:path];
//遍历字典并添加到一个动态模型数组中
NSMutableArray* messageModelsM=[NSMutableArray array];
for (NSDictionary* dict in arrayDict) {
//创建数据模型
FRMessage* messageModel=[FRMessage messageWithDictionary:dict];
//获取上一个数据模型
FRMessage* lastMessageModel=(FRMessage *)[[messageModelsM lastObject]message];
//判断当前模型的“消息发送时间”是否和上一条模型的“发送时间”一致,如果一致则做个标记
if ([messageModel.time isEqualToString:lastMessageModel.time]) {
messageModel.hideTime=YES;
}else{
messageModel.hideTime=NO;
}
//创建一个Frame模型
FRMessageFrame* messageFrameModel=[[FRMessageFrame alloc]init];
messageFrameModel.message=messageModel;
//把frame模型加到arrayModels上
[messageModelsM addObject:messageFrameModel];
}
_messageFrames=messageModelsM;
}
return _messageFrames;
}
//实现数据源方法
//返回分组数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
//返回分行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.messageFrames.count;
}
//返回单元格
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//获取模型数据
FRMessageFrame* messageFrameModel=self.messageFrames[indexPath.row];
//创建单元格
FRMessageCell* cell=[FRMessageCell messageCellWithTableview:tableView];
//给模型对象设置数据
cell.messageFrame=messageFrameModel;
//返回cell
return cell;
}
//返回每一行行高的方法
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
FRMessageFrame* messageFrame=self.messageFrames[indexPath.row];
return messageFrame.rowHeight;
}
//取消状态栏的方法
-(BOOL)prefersStatusBarHidden{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
//取消单元格的分割线
self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
//设置UITableView的背景色
self.tableView.backgroundColor=[UIColor colorWithRed:236/255.0 green:236/255.0 blue:236/255.0 alpha:1.0];
//设置UITableView的行不允许被选中
self.tableView.allowsSelection=NO;
//设置文本框最左侧有一段间距
UIView* leftView=[[UIView alloc]init];
leftView.frame=CGRectMake(0, 0, 5, 1);
//将边距设置给文本框
self.txtInput.leftView=leftView;
self.txtInput.leftViewMode=UITextFieldViewModeAlways;
}
@end
效果
3.通知与监听–通知的发布
NSNotificationCenter
发布通知
监听通知
NSNotification
对一个通知的封装
1、创建一个MacX的应用程序
2、创建一个NotificatonSender的消息发送者类
NotificatonSender.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//通知的发布者
@interface NotificationSender : NSObject
//通知发布者姓名
@property(nonatomic,copy) NSString* name;
@end
NS_ASSUME_NONNULL_END
NotificatonSender.m
#import "NotificationSender.h"
@implementation NotificationSender
@end
2、创建一个NotificatonListener的消息监听者类
NotificatonListener.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//通知的监听者
@interface NotificationListener : NSObject
//通知监听者的名称
@property(nonatomic,copy)NSString* name;
//编写一个方法,用这个方法来监听通知
-(void)method1;
@end
NS_ASSUME_NONNULL_END
NotificatonListener.m
#import "NotificationListener.h"
@implementation NotificationListener
//编写一个方法,用这个方法来监听通知
-(void)method1{
NSLog(@"监听后执行的方法");
}
//监听者被销毁时的方法
-(void)dealloc{
//移除通知
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
@end
main方法
#import <Foundation/Foundation.h>
#import "NotificationSender.h"
#import "NotificationListener.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建一个通知的发布者
NotificationSender* sender1=[[NotificationSender alloc]init];
//创建一个通知的监听者
NotificationListener* listener1=[[NotificationListener alloc]init];
//先获取NSNotificationCenter对象
NSNotificationCenter* notificationCenter=[NSNotificationCenter defaultCenter];
//向通知中心添加一个通知观察者
//addObserver:监听者,观察者,selector:监听者监听到通知后执行的方法
//name:通知的名字 ,如果不指定,则所有的(object1)发布的通知都会被监听到
//object:通知的发布者,如果不指定,所有名字为name的通知都会被监听到
[notificationCenter addObserver:listener1 selector:@selector(method1) name:@"tzname1" object:sender1];
//先监听,后发布,监听一个通知
[listener1 method1];
//让sender1对象发布一个通知
//通过NSNotificationCenter对象发布一个通知
//postNotificationName:通知的名字 object:通知的发布者 userInfo:通知的具体内容,是一个字典
[notificationCenter postNotificationName:@"tzname1" object:sender1 userInfo:@{@"title":@"疫情下的新常态",@"content":@"北京即将恢复正常秩序"}];
//移除通知
}
return 0;
}
结果:
2020-07-06 23:09:43.767547+0800 macX001Notification[5427:396141] 监听后执行的方法
2020-07-06 23:09:43.767729+0800 macX001Notification[5427:396141] 监听后执行的方法
Program ended with exit code: 0
4.通知与监听–获取监听的具体内容
修改NotificatonListener
NotificatonListener.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//通知的监听者
@interface NotificationListener : NSObject
//通知监听者的名称
@property(nonatomic,copy)NSString* name;
//编写一个方法,用这个方法来监听通知
//-(void)method1;
//编写一个方法,用这个方法来监听通知的具体内容
-(void)method1:(NSNotification*)noteInfo;
@end
NS_ASSUME_NONNULL_END
NotificatonListener.m
#import "NotificationListener.h"
@implementation NotificationListener
//编写一个方法,用这个方法来监听通知
/*
-(void)method1{
NSLog(@"监听后执行的方法");
}
*/
//监听者被销毁时的方法
-(void)dealloc{
//移除通知
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
//编写一个方法,用这个方法来监听通知的具体内容
-(void)method1:(NSNotification*)noteInfo{
NSLog(@"监听后执行的方法");
NSLog(@"%@",noteInfo);
}
@end
main方法
#import <Foundation/Foundation.h>
#import "NotificationSender.h"
#import "NotificationListener.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建一个通知的发布者
NotificationSender* sender1=[[NotificationSender alloc]init];
//创建一个通知的监听者
NotificationListener* listener1=[[NotificationListener alloc]init];
//先获取NSNotificationCenter对象
NSNotificationCenter* notificationCenter=[NSNotificationCenter defaultCenter];
//向通知中心添加一个通知观察者
//addObserver:监听者,观察者,selector:监听者监听到通知后执行的方法
//name:通知的名字 object:通知的发布者
[notificationCenter addObserver:listener1 selector:@selector(method1:) name:@"tzname1" object:sender1];
//先监听,后发布,监听一个通知
//让sender1对象发布一个通知
//通过NSNotificationCenter对象发布一个通知
//postNotificationName:通知的名字 object:通知的发布者 userInfo:通知的具体内容,是一个字典
[notificationCenter postNotificationName:@"tzname1" object:sender1 userInfo:@{@"title":@"疫情下的新常态",@"content":@"北京即将恢复正常秩序"}];
//移除通知
}
return 0;
}
结果:
2020-07-07 09:49:45.529310+0800 macX001Notification[790:19184] 监听后执行的方法
2020-07-07 09:49:45.529653+0800 macX001Notification[790:19184] NSConcreteNotification 0x1006059c0 {name = tzname1; object = <NotificationSender: 0x1005ad710>; userInfo = {
content = “\U5317\U4eac\U5373\U5c06\U6062\U590d\U6b63\U5e38\U79e9\U5e8f”;
title = “\U75ab\U60c5\U4e0b\U7684\U65b0\U5e38\U6001”;
}}
Program ended with exit code: 0
5.聊天机器人完整版
在第2节的部分上修改控制器类
ViewController.m
#import "ViewController.h"
#import "FRMessage.h"
#import "FRMessageFrame.h"
#import "FRMessageCell.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *txtInput;
//用来保存所有消息的frame模型对象的数组
@property(nonatomic,strong)NSMutableArray* messageFrames;
@end
@implementation ViewController
#pragma mark - /***懒加载数据**/
//懒加载数据
//重写messageFrames的get方法
-(NSMutableArray*)messageFrames{
if (_messageFrames==nil) {
//plist文件的路径
NSString* path=[[NSBundle mainBundle]pathForResource:@"messages.plist" ofType:nil];
//通过路径拿到所有字典
NSArray* arrayDict=[NSArray arrayWithContentsOfFile:path];
//遍历字典并添加到一个动态模型数组中
NSMutableArray* messageModelsM=[NSMutableArray array];
for (NSDictionary* dict in arrayDict) {
//创建数据模型
FRMessage* messageModel=[FRMessage messageWithDictionary:dict];
//获取上一个数据模型
FRMessage* lastMessageModel=(FRMessage *)[[messageModelsM lastObject]message];
//判断当前模型的“消息发送时间”是否和上一条模型的“发送时间”一致,如果一致则做个标记
if ([messageModel.time isEqualToString:lastMessageModel.time]) {
messageModel.hideTime=YES;
}else{
messageModel.hideTime=NO;
}
//创建一个Frame模型
FRMessageFrame* messageFrameModel=[[FRMessageFrame alloc]init];
messageFrameModel.message=messageModel;
//把frame模型加到arrayModels上
[messageModelsM addObject:messageFrameModel];
}
_messageFrames=messageModelsM;
}
return _messageFrames;
}
//实现代理方法
//实现scrollView拖动方法
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
//把键盘唤回去的思路,让控制器所管理的UIView结束编辑状态
[self.view endEditing:YES];
}
//实现文本输入框的代理方法
//当键盘上的return键被单击的时候触发
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
//1、获取用户输入的文本
NSString* text= textField.text;
//2、发送用户的消息
[self sendMessage:text withTye:FRMessageMe];
//3、发送一个系统消息
[self sendMessage:@"不认识你" withTye:FRMessageOther];
//4、清空文本框
textField.text=nil;
return YES;
}
//提取发消息方法,有两个参数
-(void)sendMessage:(NSString*)msg withTye:(FRMessageType*)type{
//2、创建一个数据模型和frame模型
FRMessage* messageModel=[[FRMessage alloc]init];
//获取当前系统时间
NSDate* nowDate=[NSDate date];
//创建一个日期时间格式化器
NSDateFormatter* fomatter=[[NSDateFormatter alloc]init];
fomatter.dateFormat=@"今天 HH:mm";
messageModel.time=[fomatter stringFromDate:nowDate];
messageModel.type=type;
messageModel.text=msg;
FRMessageFrame* modleFrame=[[FRMessageFrame alloc]init];
modleFrame.message=messageModel;
//根据当前消息的时间和上一条消息的时间,来设置是否需要隐藏时间label
FRMessageFrame* lastObjectFrame=[self.messageFrames lastObject];
NSString* lastTime=lastObjectFrame.message.time;
//如果上一条时间和此次发送的时间相等
if ([messageModel.time isEqualToString:lastTime]) {
messageModel.hideTime=YES;
}
//3、把frame模型加到集合中
[self.messageFrames addObject:modleFrame];
//4、刷新UITableView的数据
[self.tableView reloadData];
//5、把最后一行滚动到最上面
NSIndexPath* indexPath=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
//实现数据源方法
//返回分组数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
//返回分行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.messageFrames.count;
}
//返回单元格
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//获取模型数据
FRMessageFrame* messageFrameModel=self.messageFrames[indexPath.row];
//创建单元格
FRMessageCell* cell=[FRMessageCell messageCellWithTableview:tableView];
//给模型对象设置数据
cell.messageFrame=messageFrameModel;
//返回cell
return cell;
}
//返回每一行行高的方法
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
FRMessageFrame* messageFrame=self.messageFrames[indexPath.row];
return messageFrame.rowHeight;
}
//取消状态栏的方法
-(BOOL)prefersStatusBarHidden{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
//取消单元格的分割线
self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
//设置UITableView的背景色
self.tableView.backgroundColor=[UIColor colorWithRed:236/255.0 green:236/255.0 blue:236/255.0 alpha:1.0];
//设置UITableView的行不允许被选中
self.tableView.allowsSelection=NO;
//设置文本框最左侧有一段间距
UIView* leftView=[[UIView alloc]init];
leftView.frame=CGRectMake(0, 0, 5, 1);
//将边距设置给文本框
self.txtInput.leftView=leftView;
self.txtInput.leftViewMode=UITextFieldViewModeAlways;
//监听键盘的弹出事件,实际就是监听通知
//1、创建一个nsnotificationCenter对象
NSNotificationCenter* center=[NSNotificationCenter defaultCenter];
//2、监听键盘的弹出通知
[center addObserver:self selector:@selector(KeyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
//监听键盘时间后执行的方法
-(void)KeyboardWillChangeFrame:(NSNotification*)noteInfo{
/*
NSLog(@"通知名称:%@",noteInfo.name);
NSLog(@"通知发布者:%@",noteInfo.object);
NSLog(@"通知的具体内容:%@",noteInfo.userInfo);
*/
//获取键盘的Y值
CGRect rectEnd=[noteInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardY=rectEnd.origin.y;
CGFloat tranformValue=keyboardY-self.view.frame.size.height;
//用动画方式让整个view进行平移
[UIView animateWithDuration:0.25 animations:^{
//让整个view进行平移
self.view.transform=CGAffineTransformMakeTranslation(0, tranformValue);
}];
//让tableview的最后一行滚动到键盘的最上面
NSIndexPath* lastRowIndexPath=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:lastRowIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
//监听通知的对象的dealloc方法中移除监听
-(void)dealloc{
//移除通知
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
@end
结果