美文网首页iOS开发Code Reviewios开发
[程序员日记]OC常用传值方法

[程序员日记]OC常用传值方法

作者: KeyLiu7 | 来源:发表于2016-02-15 15:33 被阅读1930次

    在面向对象开发中,经常遇到多个类间传值,总结起来即正向传值(A—>B)(属性传值),反向传值(A<—B)(利用对象,使用TargetAction,使用协议代理,使用系统自带的Block,使用自定义Block),双向传值(A<—>B)(使用NSUserDefaults进行数据传值,使用系统的UIApplication单例进行传值,使用自己的单例类进行传值,使用通知中心NSNotificationCenter进行传值,使用KVC进行传值)。

    1.正向传值

    属性传值

    在B类中定义属性用于接收A类传来的数据

    2.反向传值(回调)

    1)利用对象反向传值

    将A类对象定义成B类的属性进行传值

    如,通过KGSubViewController(B)修改 KGRootViewController(A)的Label

    KGRootViewController

    //在KGRootViewController中定义函数接收返回的数据
    -(void)backValue:(NSString *)string color:(UIColor *)color
    {
        //将参数的值赋给label
        label.text = string;
    
        //将颜色赋给赋给lable的字体颜色
        label.textColor = color;
    }
    

    界面跳转至KGSubViewController,并将KGRootViewController对象传到KGSubViewController中

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
      KGSubViewController * svc = [[KGSubViewController alloc]init];
    
      //让B持有A
      svc.rvc = self;
    
      [self presentViewController:svc animated:YES completion:nil];
    }
    

    KGSubViewController

    //创建一个Root对象
    @property(nonatomic,retain) KGRootViewController * rvc;
    
    
    //在销毁之前,做一些回传数据的事
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self.rvc backValue:tf.text color:[UIColor redColor]];
    
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    2)使用TargetAction反向传值

    通过指定回传方法和回传对象进行传值

    仍以上例为例,实现方法为:
    KGRootViewController

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    
        KGSubViewController * svc = [[KGSubViewController alloc]init];
        //将回传对象进行指定
        svc.target = self;  //这里的self是指rootviewcontrller
        //将回传方法,进行指定
        svc.selector = @selector(backValue:);
    
        [self presentViewController:svc animated:YES completion:nil];
    }
    
    -(void)backValue:(NSString *)string
    {
        //回传数据方法
        label.text = string;
    }
    

    KGSubViewController

    //在这里定义两个属性,用来接收目标和方法,用来进行反向传值
    
    //接收要回传的对象
    @property(nonatomic,retain) id target; 
    
    //接收回传数据的方法
    @property(nonatomic,assign) SEL selector;
    
    //在销毁之前,将数据回传回去
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //利用保存的target 和 action 来进行回传
        if ([self.target respondsToSelector:self.selector]) {
        [self.target performSelector:self.selector withObject:tf.text];
        }
    
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    3)使用协议代理反向传值

    协议代理是回调中常用的方法,顾名思义,把某个对象要做的事情委托给别的对象去做。那么别的对象就是这个对象的代理,代理它来打理要做的事情。使用协议代理不仅可以正向传值,亦可反向传值。在使用中,需要注意哪个类是委托方,哪个类是代理方。总之:谁传值谁是委托方

    如,通过KGSubViewController改变KGRootViewController中label值

    在KGSubViewController页面里,制定一个协议

    @protocol BackValue <NSObject>
    //回传数据的协议方法
    -(void)backValue:(NSString *)string;
    @end
    
    @property(nonatomic,retain) id < BackValue > delegate;
    

    在KGSubViewController使代理方实现方法

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //代理方实现协议中的方法
        [self.delegate backValue:tf.text];
    
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    在KGRootViewController中实现协议 <BackValue>

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        KGSubViewController * svc = [[KGSubViewController alloc]init];
    
        //让A同意B所提出的协议条件
        svc.delegate = self;
    
        [self presentViewController:svc animated:YES completion:nil];
    }
    
    //实现协议 方法
    -(void)backValue:(NSString *)string
    {
        label.text = string;
    }
    

    4)使用系统自带的Block进行反向传值

    block是代码块的对象,类似函数指针,调用block如同调用代码块中的代码,利用block可以实现回调。

    在系统提供方法中,有很多使用block方法,如界面跳转presentViewController时

    将KGRootViewController中label.text值传给KGSubViewController textField.text

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        KGSubViewController * svc = [[KGSubViewController alloc]init];
    
        svc.rvc = self;
    
        //OC中,block用来去指向一个匿名的语句块,从而可以当成函数还调用该语句块
        //这个方法的第三个参数是一个block,意思说,当弹出来的svc显示完成后,执行block里的内容
        [self presentViewController:svc animated:YES completion:^{
        
             //正向传值
            svc.textField.text = self.label.text;
        }];
    }
    

    将KGSubViewController textField.text值传给 KGRootViewController中label.text

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self dismissViewControllerAnimated:YES completion:^{
        
            self.rvc.label.text = self.textField.text;
        
        }];
    }
    

    5)使用自定义Block反向传值

    KGSubViewController

    //定义一个block的属性
    @property(nonatomic,copy)void (^block)(NSString *);
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //执行block
        self.block(tf.text);
    
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    KGRootViewController

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        KGSubViewController * svc = [[KGSubViewController alloc]init];
    
        //给block赋值,做用是让svc知道block指向的代码块的功能
        svc.block = ^(NSString * string){
    
            label.text = string;
        
        };
        [self presentViewController:svc animated:YES completion:nil];
    
    }
    

    3.双向产值
    1)使用NSUserDefaults进行数据传值

    NSUserDefaults纪录本地一些轻量级的数据,是单例类。其通过userDefaults对象来将选中按钮的索引给保存到NSUserDefaults的plist文件中。这个文件实际上是一个plist文件,在沙盒中的/Library/Preferences/NSUserDefaults.plist 这个位置

    当KGSubViewController调用viewWillAppear时读取沙盒内容

    -(void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        //获取NSUserDefaults文件,读取里面内容,来决定让哪一个按钮进行选中
        NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
        //通过存的时候的key值来进行取值
        NSString * value = (NSString *)[ud objectForKey:@"ButtonIndex"];
    
        //计算出按钮的tag值
        int buttonIndex = 1000 + value.intValue;
        //利用tag值取到按钮
        UIButton * button = (UIButton *)[self.view viewWithTag:buttonIndex];
        button.selected = YES;
    }
    

    KGRootViewController
    点击button将点击按钮的索引存入沙盒中

    -(void)buttonClick:(UIButton *)button
    {
        for (int i = 1;i<6; i++) {
            UIButton * btn = (UIButton *)[self.view viewWithTag:1000+i];
            if (btn.selected == YES) {
                btn.selected = NO;
            }
        }
        button.selected = YES;
        //将每次点击选中的按钮索引给存起来
        NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
        NSLog(@"%@",[NSBundle mainBundle]);
        //通过userDefaults对象来将选中按钮的索引给保存到NSUserDefaults的plist文件中
        //这个文件实际上是一个plist文件,在沙盒中的/Library/Preferences/NSUserDefaults.plist 这个位置
        [userDefaults setObject:[NSString stringWithFormat:@"%d",button.tag - 1000] forKey:@"ButtonIndex"];
        //回写文件
        [userDefaults synchronize]; //synchronize:使同步,同时发生
    }
    

    KGRootViewController

    -(void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        //获取NSUserDefaults文件,读取里面内容,来决定让哪一个按钮进行选中
        NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
        //通过存的时候的key值来进行取值
        NSString * value = (NSString *)[ud objectForKey:@"ButtonIndex"];
    
        label.text = [NSString stringWithFormat:@"上次按下的是第 %@ 个按钮",value];
    }
    

    2)使用系统的UIApplication单例进行传值

    单例类在程序中只创建一次实例对象,利用这个特点可以进行传值。在iOS开发中,UIApplication就是个单例类,利用他可实现传值。

    在UIApplication定义存储内容

    //创建一个公共数组,用来存放数据,
    @property(nonatomic,retain) NSMutableArray * array;
    

    在相应ViewController中使用

    //应该去利用系统的UIApplication这个单例来获取系统已经创建好的那个AppDelegate里的对象
    
    //这是一个单例 对象,在整个程序中,只有一个唯一的实例存在
    UIApplication * application = [UIApplication sharedApplication];
    
    //通过这个单例对象来找到它持有的AppDelegate对象
    KGAppDelegate * appDelegate = application.delegate;
    
    //通过appDelegate对象拿到他的数组
    [appDelegate.array addObject:self.title];
    

    3)使用自己的单例类进行传值

    除了使用系统自带的单例类外,还可以使用自定义单例类用来传值

    自定义单例类KGMyApplication

    //为application类,添加一个属性,用来接收MyAppDelegate对象
    @property(nonatomic,retain) KGMyAppDelegate * delegate;
    
    
    //使用这个方法来实例一个单例对象
    +(KGMyApplication *)sharedMyApplication;
    
    +(KGMyApplication *)sharedMyApplication
    {
        static KGMyApplication * obj = nil;
        if (!obj) {
            //给obj创建单例对象
            obj = [[KGMyApplication alloc]init];
            //给单例对象的delegate属性赋值
            obj.delegate = [[KGMyAppDelegate alloc]init];
        }
        return obj;
    }
    

    定义KGMyAppDelegate类保存数据

    //这个类不是一个单例类,但是,需要在这里保存数据
    @property(nonatomic,retain)NSMutableArray * array;
    

    在相应ViewController中使用

    //首先获取MyApplication的单例对象
    
    KGMyApplication * app = [KGMyApplication sharedMyApplication];
    
    //通过这个单例对象里的delegate属性来获取MyAppDelegate对象
    
    KGMyAppDelegate * appDelegate = app.delegate;
    
    //获取MyAppDelegate里的数组
    NSMutableArray * array = [appDelegate array];
    
    static int n = 0;
    [array addObject:[NSString stringWithFormat:@"VC1-%d",n++]];
    

    4)使用通知中心NSNotificationCenter进行传值

    通知由通知中心发送,通知中心在整个工程中只有一个。通知中心可以发送多条消息,可以在整个工程中的任何位置接收消息,通过通知中心的名称区分消息。

    一个简单的应用,从界面2中发送通知,界面1中接收

    KGFirstViewController

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomeThing:) name:@"xiaoxi" object:nil];
    
    - (void)doSomeThing:(NSNotification *)noti
    {
        NSLog(@"收到了");
    
        label.text = [noti.userInfo objectForKey:@"key"];
    }
    

    KGSecondViewController

    NSNotification *noti = [[NSNotification alloc]initWithName:@"xiaoxi" object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@", btn.titleLabel.text],@"key", nil]];
        // 发送
        [[NSNotificationCenter defaultCenter] postNotification:noti];
    

    类间传值是编程时最常用的方法,也是最基础的语法。在程序中使用不同的方法可以使的程序编的更加灵活。除以上方法外,还有KVC等方法,将在后续详解。

    欢迎各位指教

    相关文章

      网友评论

      • sheepcao:貌似没考虑强弱引用,而且这里面targetAction和delegate感觉是一回事。个人理解,仅交流
      • 十二面相丶:有木有代码地址 传来看看啊 谢谢了~
        十二面相丶:@刘奇1993 非常感谢.
        KeyLiu7: @不期而愈丶 好的,晚上我传一下代码分享
      • 1度矿泉水:楼主好棒啊,学到了好多,好久不会的传值一看就懂了耶~~

      本文标题:[程序员日记]OC常用传值方法

      本文链接:https://www.haomeiwen.com/subject/erjpkttx.html