消息传递机制

使用模型传递数据

既然是使用模型传递数据。首先就要定义一个模型,比如 UserModel,新建一个类,继承NSObject(最纯洁的类),放入所需要传递的参数。
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface UserModel : NSObject  
  4.   
  5. @property(nonatomic,retainNSString *userName;  
  6. @property(nonatomic,retainNSString *gendar;  
  7. @property(assign) int age;  
  8.   
  9. @end  
#import <Foundation/Foundation.h>

@interface UserModel : NSObject

@property(nonatomic,retain) NSString *userName;
@property(nonatomic,retain) NSString *gendar;
@property(assign) int age;

@end

在界面一中:


在  .m  或者   .h  文件中  
  1. @interface ViewController ()  
  2. @property (strong,nonatomicUserModel *userModel;  
  3. @end  
@interface ViewController ()
@property (strong,nonatomic) UserModel *userModel;
@end

- (void)viewDidLoad  的时候就要初始化 UserModel 


  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     _userModel = [[UserModel alloc] init];  
  6. }  
- (void)viewDidLoad
{
    [super viewDidLoad];

    _userModel = [[UserModel alloc] init];
}

这时,你的界面一中,user对象就有3个属性, userName;  gender;   age。此时 把你需要传递的数据赋给它们,在此 仅以userName为例。

    

  1. _userModel.userName = self.userNameTextFiled.text;  
    _userModel.userName = self.userNameTextFiled.text;


接下来自然就是赋值给界面二了 
在界面二中:

在  .h  文件中(所以说 .h文件是对外开放的,不想要访问的放入.m中),同样
  1. @property (strong,nonatomicUserModel *userModel;  
@property (strong,nonatomic) UserModel *userModel;
- ( void )viewDidLoad 中 不需要初始化!输出话则数据无法传递!


返回至界面一:

在需要跳转的位置 
  1. SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:@”SecondViewController” bundle:[NSBundle mainBundle]];  
  2. //设置SecondViewController中的值  
  3. secondView.userModel = _userModel;  
  4. //跳转界面  
  5. [self presentModalViewController:secondView animated:YES];  
    SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:[NSBundle mainBundle]];
    //设置SecondViewController中的值
    secondView.userModel = _userModel;
    //跳转界面
    [self presentModalViewController:secondView animated:YES];

此时, 界面二的  userModel则有值了,值即为界面一中的self.userNameTextFiled.text。 然后在界面二中显示出来:

界面二:

  1. self.userNameTextField.text = self.userModel.userName;  
self.userNameTextField.text = self.userModel.userName;

自此,完成了界面一跳转至界面二的数据传递。
那我修改这个数据之后 需要跳回去继续传递呢?

在界面二中:
需要返回的地方
  1. self.userEntity.userName = self.userNameTextField.text;  
  2. [self dismissModalViewControllerAnimated:YES];  
    self.userEntity.userName = self.userNameTextField.text;
    [self dismissModalViewControllerAnimated:YES];
把这个值继续赋给自己的模型即可。

在界面一: 
  1. -(void)viewWillAppear:(BOOL)animated{  
  2.     [super viewDidAppear:animated];  
  3.     self.userNameTextFiled.text = self.userModel.userName;  
  4. }  
-(void)viewWillAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    self.userNameTextFiled.text = self.userModel.userName;
}

自此,完成了界面二跳转至界面一的数据传递。

注意:3个界面同样成立,只要记住:只要在第一个界面出初始化模型即可。


使用代理传递数据

其实用代理传递数据也有两种, 一种是不写代理的.h文件, 一种是用于拥有较多代理的.h文件。先介绍不写的吧,直接贴代码, 完成界面二传递数据至界面一。

不写代理的.h文件

在界面一   .m
  1. AddTime *t_vc = [[AddTime alloc] initWithNibName:@”AddTime” bundle:nil];  
  2. t_vc.delegate = (id<AddTimeDelegate>)self;  
  3. t_vc.timeArr = timeArr;  
  4. t_vc.maxCount = 2;  
  5. [self.navigationController pushViewController:t_vc animated:YES];  
            AddTime *t_vc = [[AddTime alloc] initWithNibName:@"AddTime" bundle:nil];
            t_vc.delegate = (id<AddTimeDelegate>)self;
            t_vc.timeArr = timeArr;
            t_vc.maxCount = 2;
            [self.navigationController pushViewController:t_vc animated:YES];


  1. -(void)getTime:(NSString *)Time  
  2. {  
  3.     [timeArr addObject:Time];  
  4.     [_tableView reloadData];  
  5.   
  6. }  
-(void)getTime:(NSString *)Time
{
    [timeArr addObject:Time];
    [_tableView reloadData];

}

在界面二   .h
  1. @protocol AddTimeDelegate;  
  2.   
  3. @interface AddTime : BaseViewController  
  4.   
  5. @property(nonatomic,weak)id<AddTimeDelegate> delegate;  
  6. @property(nonatomic,strong)NSMutableArray *timeArr;  
  7. @property(nonatomic,assign)NSInteger maxCount;  
  8. @property(nonatomic,assign)NSInteger type;  
  9.   
  10. @end  
  11.   
  12. @protocol  AddTimeDelegate<NSObject>  
  13.   
  14. -(void)getTime:(NSString *)Time;  
  15.   
  16. @end  
@protocol AddTimeDelegate;

@interface AddTime : BaseViewController

@property(nonatomic,weak)id<AddTimeDelegate> delegate;
@property(nonatomic,strong)NSMutableArray *timeArr;
@property(nonatomic,assign)NSInteger maxCount;
@property(nonatomic,assign)NSInteger type;

@end

@protocol  AddTimeDelegate<NSObject>

-(void)getTime:(NSString *)Time;

@end

.m
  1. [self.delegate getTime:t_str];  
  2. [self.navigationController popViewControllerAnimated:YES];  
                    [self.delegate getTime:t_str];
                    [self.navigationController popViewControllerAnimated:YES];

拥有较多代理的.h文件

转自 @ 唐韧_Ryan 

ViewController.h

  1. #import <UIKit/UIKit.h>  
  2. #import “PassValueDelegate.h”  
  3.   
  4. //第一个窗口遵守PassValueDelegate  
  5. @interface ViewController : UIViewController<PassValueDelegate>  
  6.   
  7. @property (retainnonatomic) IBOutlet UILabel *nameLabel;  
  8. @property (retainnonatomic) IBOutlet UILabel *ageLabel;  
  9. @property (retainnonatomic) IBOutlet UILabel *gendarLabel;  
  10.   
  11. - (IBAction)openBtnClicked:(id)sender;  
  12.   
  13. @end  
#import <UIKit/UIKit.h>




#import "PassValueDelegate.h" //第一个窗口遵守PassValueDelegate @interface ViewController : UIViewController<PassValueDelegate> @property (retain, nonatomic) IBOutlet UILabel *nameLabel; @property (retain, nonatomic) IBOutlet UILabel *ageLabel; @property (retain, nonatomic) IBOutlet UILabel *gendarLabel; - (IBAction)openBtnClicked:(id)sender; @end

ViewController.m

  1. //实现协议,在第一个窗口显示在第二个窗口输入的值,类似Android中的onActivityResult方法  
  2. -(void)passValue:(UserEntity *)value  
  3. {  
  4.     self.nameLabel.text = value.userName;  
  5.     self.ageLabel.text = [NSString stringWithFormat:@”%d”,value.age];  
  6.     self.gendarLabel.text = value.gendar;  
  7. }  
  8.   
  9. //点击进入第二个窗口的方法  
  10. - (IBAction)openBtnClicked:(id)sender {  
  11.     SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:@”SecondViewController” bundle:[NSBundle mainBundle]];  
  12.     //设置第二个窗口中的delegate为第一个窗口的self  
  13.     secondView.delegate = self;  
  14.       
  15.     [self.navigationController pushViewController:secondView animated:YES];  
  16.     [secondView release];  
  17. }  
//实现协议,在第一个窗口显示在第二个窗口输入的值,类似Android中的onActivityResult方法
-(void)passValue:(UserEntity *)value
{
    self.nameLabel.text = value.userName;
    self.ageLabel.text = [NSString stringWithFormat:@"%d",value.age];
    self.gendarLabel.text = value.gendar;
}

//点击进入第二个窗口的方法
- (IBAction)openBtnClicked:(id)sender {
    SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:[NSBundle mainBundle]];
    //设置第二个窗口中的delegate为第一个窗口的self
    secondView.delegate = self;

    [self.navigationController pushViewController:secondView animated:YES];
    [secondView release];
}

SecondViewController.h

  1. #import <UIKit/UIKit.h>  
  2. #import “PassValueDelegate.h”  
  3.   
  4. @interface SecondViewController : UIViewController  
  5.   
  6. @property (retainnonatomic) IBOutlet UITextField *nameTextField;  
  7. @property (retainnonatomic) IBOutlet UITextField *ageTextFiled;  
  8. @property (retainnonatomic) IBOutlet UITextField *gendarTextField;  
  9.   
  10. //这里用assign而不用retain是为了防止引起循环引用。  
  11. @property(nonatomic,assign) NSObject<PassValueDelegate> *delegate;  
  12.   
  13. - (IBAction)okBtnClicked:(id)sender;  
  14. - (IBAction)closeKeyboard:(id)sender;  
  15.   
  16. @end  
#import <UIKit/UIKit.h>




#import "PassValueDelegate.h" @interface SecondViewController : UIViewController @property (retain, nonatomic) IBOutlet UITextField *nameTextField; @property (retain, nonatomic) IBOutlet UITextField *ageTextFiled; @property (retain, nonatomic) IBOutlet UITextField *gendarTextField; //这里用assign而不用retain是为了防止引起循环引用。 @property(nonatomic,assign) NSObject<PassValueDelegate> *delegate; - (IBAction)okBtnClicked:(id)sender; - (IBAction)closeKeyboard:(id)sender; @end

SecondViewController.m

  1. - (IBAction)okBtnClicked:(id)sender {  
  2.     UserEntity *userEntity = [[UserEntity alloc] init];  
  3.     userEntity.userName = self.nameTextField.text;  
  4.     userEntity.gendar = self.gendarTextField.text;  
  5.     userEntity.age = [self.ageTextFiled.text intValue];  
  6.       
  7.     //通过委托协议传值  
  8.     [self.delegate passValue:userEntity];  
  9.     //退回到第一个窗口  
  10.     [self.navigationController popViewControllerAnimated:YES];  
  11.       
  12.     [userEntity release];  
  13. }  
  14.   
  15. /*单击屏幕其他区域关闭键盘的方法 
  16.  实现方法是:首先选中xib文件的view,设置class为UIControl 
  17.  然后在事件中选择Touch Down拖线到.h文件中声明该方法,最后实现下面即可 
  18.  */  
  19. - (IBAction)closeKeyboard:(id)sender {  
  20.     [self.nameTextField resignFirstResponder];  
  21.     [self.ageTextFiled resignFirstResponder];  
  22.     [self.gendarTextField resignFirstResponder];  
  23. }  
- (IBAction)okBtnClicked:(id)sender {
    UserEntity *userEntity = [[UserEntity alloc] init];
    userEntity.userName = self.nameTextField.text;
    userEntity.gendar = self.gendarTextField.text;
    userEntity.age = [self.ageTextFiled.text intValue];

    //通过委托协议传值
    [self.delegate passValue:userEntity];
    //退回到第一个窗口
    [self.navigationController popViewControllerAnimated:YES];

    [userEntity release];
}

/*单击屏幕其他区域关闭键盘的方法
 实现方法是:首先选中xib文件的view,设置class为UIControl
 然后在事件中选择Touch Down拖线到.h文件中声明该方法,最后实现下面即可
 */
- (IBAction)closeKeyboard:(id)sender {
    [self.nameTextField resignFirstResponder];
    [self.ageTextFiled resignFirstResponder];
    [self.gendarTextField resignFirstResponder];
}

PassValueDelegate.h

  1. #import <Foundation/Foundation.h>  
  2. @class UserEntity;  
  3.   
  4. @protocol PassValueDelegate <NSObject>  
  5.   
  6. -(void)passValue:(UserEntity *)value;  
  7.   
  8. @end  
#import <Foundation/Foundation.h>
@class UserEntity;

@protocol PassValueDelegate <NSObject>

-(void)passValue:(UserEntity *)value;

@end

使用通知Notification

要在代码中的两个不相关的模块中传递消息时,通知机制是非常好的工具。通知机制广播消息,当消息内容丰富而且无需指望接受者一定要关注的话这一招特别有用。

通知可以用来发送任意消息,甚至可以包含一个userInfo字典。你可以继承NSNotification 写一个自己的通知类类自定义行为,通知的独特之处在于,发送者和接受者不需要相互知道对方,所以通知可以被用来在不同的相隔很远的模块之间传递消息。这就意味着这种消息的传递是单向的,我们不能回复通知。

这是一种“同步的”消息通知机制,观察者只要向消息中心注册,即可接受其他对象发送来的消息,消息发送者和接收者两者可以互相一无所知,完全解耦。

这种消息通知机制可以应用于任何对象,观察者可以有多个,所以消息具有广播的性质。需要注意的是,观察者向消息中心注册以后,在不需要接收消息是需要从消息中心移除。

这种消息传递机制是典型的观察者模式。

使用这种消息机制的步骤:

1.观察者注册消息通知

   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getUserProfileSuccess:) name:@"Notification_GetUserProfileSuccess" object:nil];
  • notificationobserver观察者:self
  • notificationselector处理消息的方法名:getUserProfileSuccess
  • notificationName消息通知的名字:Notification_GetUserProfileSuccess
  • notificationSender消息发送者:表示接收哪个发送者的通知,为nil则接收所有发送者的通知

2.发送消息通知

[[NSNotificationCenter defaultCenter] postNotificationName:@"Notification_GetUserProfileSuccess" 
object:userProfile userInfo:nil];
  • notificationName 消息通知的名字: Notification_GetUserProfileSuccess
  • notificationSender 消息发送者: userProfile

3.观察者处理消息

  1. - (void) getUserProfileSuccess: (NSNotification*) aNotification  
  2. {  
  3. self.userProfile = [aNotification object];  
  4.   
  5. lblName.text = self.userProfile.Name;  
  6. lblEENO.text = self.userProfile.EENO;  
  7. lblNric.text = self.userProfile.NRIC;  
  8. lblBirthday.text =self.userProfile.Birthday;  
  9. lblHireDate.text = self.userProfile.Hiredate;  
  10.   
  11. txtMobilePhone.text = self.userProfile.Mobile;  
  12. txtEmail.text = self.userProfile.Email;  
  13. }  
- (void) getUserProfileSuccess: (NSNotification*) aNotification
{
self.userProfile = [aNotification object];

lblName.text = self.userProfile.Name;
lblEENO.text = self.userProfile.EENO;
lblNric.text = self.userProfile.NRIC;
lblBirthday.text =self.userProfile.Birthday;
lblHireDate.text = self.userProfile.Hiredate;

txtMobilePhone.text = self.userProfile.Mobile;
txtEmail.text = self.userProfile.Email;
}

NSNotification 接受到的消息信息,主要含:

  • Name: 消息名称 Notification_GetUserProfileSuccess
  • object: 消息发送者 userProfile
  • userInfo: 消息传递的数据信息

4.观察者注销,移除消息观察者

虽然在 iOS 用上 ARC 后,不显示移除 NSNotification Observer 也不会出错,但是这是一个很不好的习惯,不利于性能和内存。

注销观察者有2个方法:

a. 最优的方法,在 UIViewController.m 中:

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

b. 单个移除:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"Notification_GetUserProfileSuccess" object:nil];
注:按照我所理解,先在界面一注册一个观察者,这个观察者可以改变当前页面的数据,然后在第二个界面发送通知,让界面一接收通知并且执行事件。这说明不能直接从界面一去改变界面二的数据,因为必须先注册后接收。要想改变二,就要先进入界面二注册,此时肯定是不会传递数据的,因为还未注册。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值