iOS史上最全界面跳转传值总结及分析-包括属性传值、代理传值、通知传值、单例传值、代码块传值

iOS史上最全界面跳转传值总结及分析-包括属性传值、代理传值、通知传值、单例传值、代码块传值

界面跳转传值实际上就是将数据从一个界面传送给另一个界面,本文中的传值是基于UINavigationController,首先在AppDelegate里面创建一个UINavigationController,把ViewController作为其跟视图,别忘了在AppDelegate.m导入ViewController.h。代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    

    self.window = [[UIWindowalloc]initWithFrame:[UIScreenmainScreen].bounds];

    UINavigationController * nav = [[UINavigationControlleralloc]initWithRootViewController:[ViewControllernew]];

    self.window.rootViewController = nav;

    nav.navigationBar.translucent =NO;

    [self.windowmakeKeyAndVisible];

    return YES;

}

    新建一个继承于UIViewController的视图控制器,本文命名为NextViewController并令ViewController为A,NextViewController为B。并在两个控制器分别放上一个button和一个label,label作为属性,button可以作为局部变量只要增加一个点击事件就可;

    在ViewDidLoad中加入如下代码:

    self.view.backgroundColor = [UIColorblueColor];

    UIButton * btnProperty = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];

    btnProperty.frame =CGRectMake(100,60, 175, 40);

    [btnProperty setTitle:@"属性传值"forState:UIControlStateNormal];

    [btnProperty addTarget:selfaction:@selector(btnProperty)forControlEvents:UIControlEventTouchUpInside];

    [btnProperty setBackgroundColor:[UIColorgreenColor]];

    [self.viewaddSubview:btnProperty];

    [self.viewaddSubview:self.lblProperty];


    另外给self.lblProperty做一个懒加载

- (UILabel *)lblProperty{

    if (!_lblProperty) {

        _lblProperty = [[UILabelalloc]initWithFrame:CGRectMake(100,20, 175, 30)];

       _lblProperty.backgroundColor = [UIColorwhiteColor];

    }

    return_lblProperty;

}

    在NextViewController也加入相同代码,只需把界面颜色换一下区分开即可;每种传值都需要添加button个label,厦门就不在重复了;

1.属性传值

属性传值即给相应的ViewController定义一个外部可用的属性,在界面跳转时来传送相应的值,所有传值都可分为A-->B和B-->A,其中A为跟视图,B为新视图。

(1)属性传值A-->B

通过属性由A传值到B不难理解,只需要在B界面定义一个属性,在A PUSH到B的时候把需要传送的内容赋值给B对应的属性即可,代码如下:

 在NextViewController.h 定义一个属性(本文以字符串为例):

@property (nonatomic,strong) NSString  * strProperty2;

           ②在ViewController中的点击事件做如下操作:

//属性传值

- (void)btnProperty{

    

    NextViewController * nextVC = [[NextViewControlleralloc]init];

    nextVC.strProperty2 =@"厦门博看文思";

    [self.navigationControllerpushViewController:nextVC animated:YES];

}

     ③这时B控制器已经拿到了A传来的值,只需要在viewDidLoad做个赋值操作即可展现出传过来的字符串了:

//属性传值

    self.lblProperty.text =self.strProperty2;

(2)属性传值B-->A

    属性由B到A传值会比A到B稍微复杂一点不过也是分为三步:

①给A定义一个外部可用属性:

@property (nonatomic,strong) NSString * strProperty1;

②在B跳转回A的点击事件中找到A控制器并给其属性赋值,这里拿到A控制器就不能跟A-->B那样直接新建一个控制器了,因为A控制器还存在,只是没有显示出来而已;所以应该通过导航栏控制器中获取当前A控制器:

- (void)btnProperty{

    ViewController * VC =self.navigationController.viewControllers[0];

    VC.strProperty1 =@"iOS";

    [self.navigationControllerpopViewControllerAnimated:YES];

}

③这时A中已经拿到了B传过来的值,但是要显示的话应该在viewWillAppear中:

- (void)viewWillAppear:(BOOL)animated{

//    属性传值

    self.lblProperty.text =self.strProperty1;

}

2.代理传值

(1)代理传值A-->B

①在A控制器的头文件申明协议:

@protocol ViewControllerDelegate <NSObject>

@optional

- (void)delegateSendToNext:(NSString * )strDelegate;


@end


并在@interface中添加遵循协议的代理属性
@property (nonatomic,assign)id<ViewControllerDelegate> delegate;

③在B的头文件中遵循A的协议;

@interface NextViewController :UIViewController<ViewControllerDelegate>

在A跳转到B的点击事件中,让B界面成为A的代理,并调用代理方法;

//代理传值

- (void)btnDelegate{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

   self.delegate = nextVC;

    [self.delegatedelegateSendToNext:@"厦门博看文思"];

    [self.navigationControllerpushViewController:nextVC animated:YES];

}


⑤在B控制器实现A协议中的方法完成传值。

//在B控制器实现A控制器中的代理方法

- (void)delegateSendToNext:(NSString * )strDelegate{

   self.lblDelegate.text = strDelegate;

}


(2)代理B-->A

①在B控制器头文件申明协议;

@protocol NextViewControllerDelegate <NSObject>


@optional

- (void)delegateSend:(NSString *)strDelegate;


@end


②在B控制器定义遵循协议的属性;

@property (nonatomic,assign) id<NextViewControllerDelegate> delegate;


③在B跳回A的点击事件中调用代理方法;

- (void)btnDelegate{

    

    [self.delegatedelegateSend:@"iOS"];

    [self.navigationControllerpopViewControllerAnimated:YES];


}

④A遵循B的协议;

@interface ViewController ()<NextViewControllerDelegate>

⑤在A跳转到B的点击事件中使A成为B的代理者;

//代理传值

- (void)btnDelegate{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

    nextVC.delegate =self;

    [self.navigationControllerpushViewController:nextVC animated:YES];

}


⑥在A控制器实现B协议中的代理方法;

//代理方法

- (void)delegateSend:(NSString *)strDelegate{

   self.lblDelegate.text = strDelegate;

}


3.通知传值

    通知传值的核心部分,就是建立好监听者与发送者在时间上的关系,即一定要先有监听者在去发送通知,掌握好了这一点就可以玩转通知传值。

(1)通知传值A-->B

①B是消息的接收者,要在A发送消息之前先建立好监听者,这时候就需要在B中重写init方法来达到这个目的,然后写受到通知后的操作,最后一定要记得移除监听者;

- (instancetype)init{

   if (self = [superinit]) {

       //创建监听者

        [[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(changeValue:)name:@"bobo"object:nil];

        

    }

    return self;

}

//通知传值

- (void)changeValue:(NSNotification *)notification{

   NSDictionary * dict = notification.userInfo;

   self.lblNotification.text = dict[@"key"];

}

//移除监听者

- (void)dealloc{

    [[NSNotificationCenterdefaultCenter] removeObserver:selfname:@"bobo"object:nil];

}


②接下来就是在A的点击事件中添加发送消息即可。

//通知传值

- (void)btnNotification{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

    

   NSNotification * notification = [[NSNotificationalloc]initWithName:@"bobo"object:nil userInfo:@{@"key":@"厦门博看文思"}];

//发送通知

    [[NSNotificationCenterdefaultCenter] postNotification:notification];

    [self.navigationControllerpushViewController:nextVC animated:YES];

}

(2)通知传值B-->A

①由B到A传值就更简单了,因为时间顺序上一定是先有A后有B,所以只要在A的viewDidLoad中建立一个监听者,然后实现监听事件,最后一处监听者就行

    //在viewDidLoad中注册监听者

    [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(changeValue:)name:@"bobo2"object:nil];



//收到通知后操作

- (void)changeValue:(NSNotification *)notification{

   NSDictionary * dict = notification.userInfo;

   self.lblNotification.text = dict[@"key"];

}

//移除监听者

- (void)dealloc{

    [[NSNotificationCenterdefaultCenter]removeObserver:selfname:@"bobo2"object:nil];

}

②在B跳转回A的时候发送通知就行了。

- (void)btnNotification{

   NSNotification * notification = [[NSNotificationalloc]initWithName:@"bobo2"object:nil userInfo:@{@"key":@"iOS"}];

    //发送通知

    [[NSNotificationCenterdefaultCenter] postNotification:notification];

    [self.navigationControllerpopViewControllerAnimated:YES];


}


4.单例传值

单例,就是从程序开始到程序结束不管中途怎么去实例化都只有一个实例对象,先创建一个单例(本文就随便写了个Teacher类作为单例):

//Teacher.h

#import <Foundation/Foundation.h>


@interface Teacher :NSObject<NSCopying,NSMutableCopying>

@property (nonatomic,strong) NSString * name;

@property (nonatomic,assign) int age;

+ (instancetype)shareInstance;

@end


//Teacher.m

#import "Teacher.h"


staticTeacher * teacher = nil;

@implementation Teacher


+ (instancetype)shareInstance{

    

   static dispatch_once_t onceToken;

   dispatch_once(&onceToken, ^{

       teacher = [[Teacheralloc]init];//确保对象只被初始化一次

    });


    returnteacher;

}


+ (instancetype)allocWithZone:(struct_NSZone *)zone{

   if (teacher ==nil) {

       teacher = [[superallocWithZone:zone]init];

    }

    returnteacher;

}


- (instancetype)copyWithZone:(NSZone *)zone{

    returnteacher;

}


- (id)mutableCopyWithZone:(nullableNSZone *)zone{

    returnteacher;

}


@end



(1)单例传值A-->B

①单例传值只要在A中拿到单例对象,给对象属性赋值,都在跳转事件执行;

//单例传值

- (void)btnInstance{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

   Teacher * teacher = [Teachernew];

    teacher.name =@"厦门博看文思";

    [self.navigationControllerpushViewController:nextVC animated:YES];

}

②在B界面拿到单例对象在给label赋值就行,在viewDidLoad写如下代码即可:

    //单例传值

   Teacher * teacher = [Teachernew];

   self.lblInstance.text = teacher.name;

(2)单例传值B-->A

①由B界面跳回A界面也是跟A一样在跳转事件给单例对象赋值:

- (void)btnInstance{

    //单例传值

   Teacher * teacher = [Teachernew];

    teacher.name =@"iOS";

    [self.navigationControllerpopViewControllerAnimated:YES];

}

②但是A界面拿到单例值需要在viewWillAppear中去赋值:

- (void)viewWillAppear:(BOOL)animated{

//    单例传值

   Teacher * teacher = [Teachernew];

   self.lblInstance.text = teacher.name;

}


5.代码块传值

代码块传值很好用很方便,但是理解上需要花点功夫,接下来咱就一步一步去分析完成;

(1)代码块传值A-->B

①代码块由A传值到B需要现在B的头文件中定义一个外部可用代码块属性;

@property (nonatomic,strong) void(^oneBlock)(NSString *) ;

然后在B的给代码块赋值,但是赋值一定要在A中调用之前完成,因此也需要重写B的init方法

- (instancetype)init{

   if (self = [superinit]) {

        //代码块传值a---->b

       NextViewController * nextVC = self;

       _oneBlock = ^(NSString *strBlock){

                nextVC.lblBlock.text = strBlock; 

        };

        

    }

    return self;

}

③在A跳转到B的点击事件中调用代码块;

//代码块传值

- (void)btnBlock{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

    //a---->b

   if (nextVC.oneBlock) {//调用代码块前一定要先判断代码块是否为空,调用空的代码块会直接使系统奔溃

//跳会主线程掉用代码块

        dispatch_async(dispatch_get_main_queue(), ^{

             nextVC.oneBlock(@"厦门博看文思");

        });

    }

    [self.navigationControllerpushViewController:nextVC animated:YES];

}


(2)代码块传值B-->A

①代码块传值由B到A也在B的头文件看中定义一个外部可用代码块属性;

@property (nonatomic,strong) void(^myBlock)(NSString *) ;

②不过这时候代码块赋值操作应该在A的点击事件中进行,因为需要在B中调用代码块传送一个字符串回到A中;

//代码块传值

- (void)btnBlock{

    NextViewController * nextVC = [[NextViewControlleralloc]init];

    //b---->a

    nextVC.myBlock = ^(NSString * strBlock){

            self.lblBlock.text = strBlock ;

    };

    [self.navigationControllerpushViewController:nextVC animated:YES];

}

③在B跳转回A点击事件中调用代码块完成传值。

- (void)btnBlock{

    //代码块传值b----->a

   if (_myBlock) {

        dispatch_async(dispatch_get_main_queue(), ^{

           _myBlock(@"iOS");

        });

        

    }

    [self.navigationControllerpopViewControllerAnimated:YES];


}

6.界面跳转传值总结

    (1)一般A-->B使用属性传值,单例传值一般可用于A跳转到多个界面,这多个界面都需要用到A的值的情况;
    (2)一般B-->A使用代码块或者代理传值更为方便,使用通知传值也很方便不过一般情况不推荐使用通知传值,通知传值用多了有可能导致系统奔溃。


        






  









评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值