IOS开发教程第一季之01UI基础day8合并IOS学习008----控件(UITableView04聊天机器人)

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

结果
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值