iOS中页面传值和页面跳转

对于各种软件来说,都离不开页面的跳转和页面的传值。

ios的页面通信

开发过程中我们在页面传值时我们通常使用的方法有:属性传值法,block传值法,代理传值法,以及单例传值法,通知传值法。

属性传值

属性传值多用于在将前一个页面的值传到后一个页面去,也就是我们通常说的从前往后传值,

当第一个页面push到第二个页面的时候.我们在第二个页面声明一个属性用于接受从第一个页面传递过去的值,然后在push这个事件被触发的时候进行赋值.
也就是说,先初始化创建第二个控制器(页面),然后通过创建的控制器来访问它所对应的属性,将即将传递的值赋给它,这样就完成了属性传值.于是当页面(控制器)被push到第二个页面之后我们访问它的属性的时候,也就顺便获取到了传递过来的值.

1
2
3
4
5
6
-(void)next:(UINavigationController *)sender{
ScondViewController *secondNC = [[ScondViewController alloc] init];
// 将第一个界面的输入框信息赋值给第二个页面的Label
secondNC.tfString = _firstTF.text;
[self.navigationController pushViewController:secondNC animated:YES];
}

代理传值

代理传值多用于从后往前传值.只要在协议中声明一个协议方法,然后两个类一个作为委托方一个作为遵守方来调用和实现方法就可以实现传值。十分高效而且针对性很强。委托者:声明delegate属性,调用协议方法。被委托者:遵守协议,设定被委托者,覆写协议方法。

  1. 我们在SecondViewController的.h中创建一个协议,并且设置代理属性,让其遵循该协议.
    // 设置一个协议方法
    @protocol SecondVCDelegate
    // 代理传值

    • (void)passValue:(NSString *)value;
      @end
  2. 声明代理属性进行代理传值
    @property(nonatomic,weak)id delegate;

  3. SecondViewController的导航控制器设置了右按钮(返回按钮),那么,我们只需要在其触发事件(back:)中调用代理方法去执行传值即可.
    代码如下:

1
2
3
4
5
- (void)back:(UINavigationController *)sender{
// 代理去执行传值
[_delegate passValue:_secondTF.text];
[self.navigationController popViewControllerAnimated:YES];
}
  1. 然后在FirstViewController的next方法中为SecondNC制定其代理为其自身即可.
  2. 实现其代理方法
    1
    2
    3
    - (void)passValue:(NSString *)value{
    _firstLab.text = value;
    }

这样我们就可以在第一个页面得到第二个页面的值了.

block传值

block的本质就和其他OC中变量类似,只不过,block中存储的数据是函数体,但是在使用block时完全可以像调用其他函数似的,传入参数,然后得到返回值.从后往前传值.

  1. 在SecondViewController中定义并声明block属性.

    1
    2
    3
    4
    5
    // 定义有参无返回值的匿名函数(传递字符串)
    typedef void(^MyBlock)(NSString *);
    @interface SecondViewController : UIViewController
    @property(nonatomic,copy)MyBlock block;
    @end
  2. 我们在SecondViewController的back方法中调用block,并且将在这个控制器的textField中的文字作为block的参数传递给block.

1
2
3
4
5
- (void)back:(UINavigationController *)sender{
// 代理去执行传值
self.block(_secondTF.text);
[self.navigationController popViewControllerAnimated:YES];
}
  1. FirstViewController的next方法中,也就是alloc出SecondViewController的时候调用SecondViewController的block,实现传值
    1
    2
    3
    4
    5
    6
    7
    8
    - (void)back:(UINavigationController *)sender{
    __weak typeof(self)temp = self;
    secVC.block = ^(NSString *string){
    // 通过回调将传进来的字符串赋值给label
    temp.firstLab.text = string;
    };
    [self.navigationController popViewControllerAnimated:YES];
    }

在上述代码中,因为block里面不能直接使用属性,实例变量和方法(因为会造成循环引用),所以我们重新用__weak修饰self并重新命名为temp.这样我们就实现了传值.

通知传值

类似于广播的一种传值模式,十分简单易用。一般负责在两个不同的类之间传值,且耦合度很低。这种方式中NSNotificationCenter担任一个中介者的身份,已提供观察者与被观察者相互传递信息。

Objective-C中使用NSNotifation表示通知,每个NSNotifation对象都具有名称name(NSNotificationCenter根据该名称检索此通知的所有观察者)、来源对象Poster-object(发布该通知的对象)和可选的userInfo字典(来源对象需要告诉观察者的额外信息NSDictionary)。

NSNotificationCenter就相当于一个俱乐部,只要一行代码一个类就能加入其中成为会员(Observer向NSNotificationCenter注册感兴趣信息),当然这个类要告诉俱乐部它对哪些信息感兴趣,当有新的信息出现时,俱乐部会询问每一位会员这个信息是否是它们所需要的(Poster向NSNotificationCenter发送通知)。

  1. 在ViewController中添加观察者

    1
    2
    3
    4
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    //通知中心添加观察者
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLabelText:) name:@"改变名称" object:nil];
    }
  2. 在ViewController.m中实现观察者接到消息之后执行的方法

    1
    2
    3
    4
    -(void)changeLabelText:(NSNotification*)sender
    {
    self.NameLabel.text=sender.userInfo[@"名字"];
    }
  3. 在NextViewController.m中发送消息

    1
    2
    3
    4
    5
    6
    7
    8
    //通知中心发送通知
    -(IBAction)NSNotificationAction:(UIButton *)sender {
    NSDictionary* dic=@{@"名字":self.nameTextField.text};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"改变名称" object:nil userInfo:dic];
    [self dismissViewControllerAnimated:YES completion:^{

    }];
    }
  4. 在ViewController.m中要移除观察者

    1
    2
    3
    4
    5
    //移除通知中心
    -(void)dealloc
    {
    [[NSNotificationCenter defaultCenter]removeObserver:self];
    }

常用方法:

+ (NSNotificationCenter *)defaultCenter;

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;

本地通知和远程推送通知

  1. 本地通知:由本应用负责调用,只能从当前设备上的iOS发出。
    远程通知:由远程服务器上的程序发送至Apple Push Notification service(APNs),再由APNs把消息推送住设备上对应的程序。
  2. 本地通知是一个UILocalNotification对象,创建这个对象以后,就可以通过UIApplication的两个方法来发送通知了。
    - (void)presentLocalNotificationNow:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0) __TVOS_PROHIBITED;
    - (void)scheduleLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0) __TVOS_PROHIBITED; // copies notification

- (void)cancelLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0) __TVOS_PROHIBITED;
- (void)cancelAllLocalNotifications NS_AVAILABLE_IOS(4_0) __TVOS_PROHIBITED;

  1. 远程通知
    UIApplication中注册远程push通知:
    - (void)registerForRemoteNotifications NS_AVAILABLE_IOS(8_0);

- (void)unregisterForRemoteNotifications NS_AVAILABLE_IOS(3_0);
调用下面方法:(重写应用程序委托类的3个方法)
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken NS_AVAILABLE_IOS(3_0);

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error NS_AVAILABLE_IOS(3_0);-

单例传值

由于单例在内存中只创建一次的并且可以全局访问的属性,我们可以在必要的时候将数据存放在单例的属性中,并且在必要的时候从单例中通过访问其属性进行调用,这样就实现值的传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface DataHandle : NSObject
// 创建单例
+ (instancetype)sharedDataHandle;
@property(nonatomic,strong)NSString *Str;
@end
@implementation DataHandle
// 声明静态区对象的原因,希望程序运行期间,在内存中一直存在,这样对外界来说,可以随时读取数据
static DataHandle *dataHandle = nil;
// 创建单例(全局区)
+ (instancetype)sharedDataHandle{
if (nil == dataHandle) {
// 我们创建单例使用加号方法的原因是因为,在创建之前,无法存在一个实例对象去调用动态方法来创建它本身
dataHandle = [[DataHandle alloc] init];
}
return dataHandle;
}
@end

我们只需要在需要的时候通过其类方法(+ (instancetype)sharedDataHandle)来创建出单例对象来,然后将textField的text属性以赋值的方式赋给单例的Srt属性即可.

文章目录
  1. 1. ios的页面通信
    1. 1.1. 属性传值
    2. 1.2. 代理传值
    3. 1.3. block传值
    4. 1.4. 通知传值
      1. 1.4.1. 本地通知和远程推送通知
    5. 1.5. 单例传值
本站总访问量 本站访客数人次 ,