玩技术,爱生活
记录工作与生活的点点滴滴

详解IOS中参数传递的几种方式(3)

在第一部分中实现了自定义聊天输入的VoiceBanner,当时只实现了界面部分,所以这一部分将通过3种方法来实现输入文字后,刷新聊天界面的功能。在这一部分,你将了解到代理、block、通知这3个知识点的简单应用。

1、实现UITextField代理方法

正常情况下,我们点击文本框会弹出键盘,如下图所示。 ![键盘]http://www.moondev.cn/wp-content/uploads/2016/01/keyboard-1.png)
注意,图中红色部分,我们可以通过设置UITextFieldreturnKeyType属性来设置该按键显示的文字,比如:完成、发送、下一步等等:

// 我们这里是聊天应用,所以键盘显示“发送”即可
_msgTextField.returnKeyType = UIReturnKeySend;

设置后的效果如下: 键盘2

我们描述一下一个常规的发送消息过程:首先输入文本 –> 点击send –> 聊天界面刷新显示最近的消息。所以,我们需要监听点击send键的事件,以便我们进行下一步操作。在IOS中,我们通过实现UITextField的代理方法textFieldShouldReturn来监听此事件,比如下面的示例代码:

// 点击send按键后,在日志中打印出输入的文本
- (BOOL)textFieldShouldReturn:(UITextField *)msgTextField {
    NSLog(@"%@",msgTextField.text);
    return YES;
}

接下来我们要解决的问题就是,怎样将获取到的文本传给聊天界面的UITableView呢?我们可以通过下文的3种方法来实现。

2、自定义代理方法

实现代理的目的是要将在自定义控件VoiceBanner中输入的文字传递给UITableView,所以我们在自定义控件中增加一个msgContent属性用于存放输入的文本消息,然后定义代理方法,代理方法的参数为self,这样,当ViewController(委托对象)实现自定义控件的代理方法时,就可以获取到VoiceBanner对象,进而获取到输入的文本。所以,VoiceBanner的定义如下:

#import <UIKit/UIKit.h>
// 定义代理方法
@class VoiceBanner;
@protocol VoiceBannerDelegate <NSObject>
// 代理方法可选择实现
@optional
// 发送消息
- (void) sendMessage:(VoiceBanner *) banner;
@end

@interface VoiceBanner : UIView
// 属性中新增 msgContent和delegate
// 消息正文,用于外部获取
@property (copy,nonatomic) NSString *msgContent;
// 代理
@property (assign,nonatomic) id<VoiceBannerDelegate> delegate;

@end

UITextField的代理方法textFieldShouldReturn就应该做如下修改:

- (BOOL)textFieldShouldReturn:(UITextField *)msgTextField {
    // 将获取到的文本赋值给对象属性
    self.msgContent = msgTextField.text;
    // 判断代理对象是否实现了 sendMessage方法,如果实现了代理方法再调用代理的sendMessage方法
    if ([self.delegate respondsToSelector:@selector(sendMessage:)]) {
        [self.delegate sendMessage:self];
    }
    // 调用sendMessage方法后,然后将文本框置空
    self.msgTextField.text = @"";
    return YES;
}

最后就是ViewController实现代理方法:

- (void) sendMessage:(VoiceBanner *)banner {
    [self addmessage:banner.msgContent type:MessageMySelf];
}
- (void)addmessage:(NSString *)text type:(MessageType)type
{
    //1. 添加模型数据
    // 根据接收到的文本,创建message数据模型,然后将Message添加到table的数据源数组中去
    Message *msg = [[Message alloc]init];
    [self.messages addObject:fm];
    //2.刷新表格
    [self.chatTableView reloadData];
}

最后需要注意的一点就是,别忘了在ViewController中给delegate赋值。

3、block

其实通过Block实现参数传递,跟使用代理的原理是一致的,但是通过block来实现,我们就不需要定义msgContent属性了,我们可以直接将消息文本作为block的参数,这样代码量更少,更简单,具体的实现如下:我们首先在定义控件VoiceBanner.h中声明block

typedef void(^VoiceBannerBlock)(id);

然后定义block属性:

#import <UIKit/UIKit.h>
typedef void(^VoiceBannerBlock)(id);
@interface VoiceBanner : UIView

// 其他属性....
// Block属性
@property(nonatomic,copy) VoiceBannerBlock block;

@end

然后在实现UITextField的代理方法textFieldShouldReturn

- (BOOL)textFieldShouldReturn:(UITextField *)msgTextField {
    if (self.block) {
        self.block(msgTextField.text);
    }
    self.msgTextField.text = @"";
    return YES;
}

最后在ViewController中给block赋值:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.voiceView.block = ^(NSString *msg) {
        // 定义数据模型
        // 刷新数据
        .......
    };
}

4、使用通知

使用通知的原理很简单,在点击send按键时,向消息中心推送一个消息。ViewController向消息中心注册一个监听者,当有消息推送到消息中心后,会把此消息发送给相关的监听者,一旦监听者收到此消息就可以获取到具体的聊天内容,接着就可以构建消息模型,刷新聊天界面。

实现UITextField的代理方法:

- (BOOL)textFieldShouldReturn:(UITextField *)msgTextField {
    // 向消息中心推送一个消息,消息名称:sendMessage,消息内容对象:text
    [[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:msgTextField.text userInfo:nil];
    self.msgTextField.text = @"";
    return YES;
}

然后在ViewController中添加观察者,监听消息中心,一旦消息中心推送sendMessage消息,就执行对应的方法,这里是notiClick

- (void)viewDidLoad {
    [super viewDidLoad];
    // 接收到通知的处理过程在 noticlick中实现
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiClick:) name:@"sendMessage" object:nil];
}

最后定义接收到通知时的处理过程:

- (void) notiClick:(NSNotification *) notify {
    // 创建数据模型,刷新数据
    [self addmessage:notify.object type:MessageMySelf];
}

// 这个方法是在控制器销毁的时候调用
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

这里需要注意的是当ViewController销毁时,我们需要取消订阅消息,也就是从NSNotificationCenter移除观察者,所以在dealloc方法中需要执行removeObserver操作。

由于NSNotificationCenter在整个应用程序的生命周期内是单例的,所以NSNotificationCenter消息的接收和发送同步的,如果使用大量的通知,有可能会造成消息接收不及时,导致响应相对缓慢,所以我个人不建议各个控件,各个ControllerView之间的参数传递使用通知,建议使用block

本站文章除注明转载外,均为原创文章。 Creative Commons LicenseMOONDEV创作,采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
分享到:更多 ()