代理传值-不同类之间参数传递

概要

很多时候,不同的类之间需要有数值交流传递,但是这些类之间并没有直接的关系,比如当一个界面向子页面传递某个参数,而子页面修改某些值之后而再返回主页面的时候,主页面的UI需要根据子页面的状态做一定的UI更新,这时,就需要考虑参数传递的问题了。这里使用IOS的代理的特点,以担当参数传递的职责。

主要技术点

  • 本例子的实验效果如下所示

    其中主页面输入的用户ID是通过代理(用户信息代理)的方式传递给子页面(用户信息页面)的,因此用户信息界面根据传递的用户ID查找用户头像,并生成一些信息,同时在用户信息里面通过代理(用户信息代理)设置主页面的用户头像,具体效果上图的动画已有演示。

  • 用户信息代理协议如下
    @protocol UserInfoDelegate <NSObject>
    
    @required
    /**
     *  获取用户Id
     *
     *  @return 用户ID
     */
    - (NSString*)userId;
    
    @optional
    /**
     *  默认头像
     */
    - (void) setPortraitPath:(NSString*)portrait;
    
    @end

    该协议有两个方法,方法userId是用于传进参数,方法setPortraitPath:用于传出参数,这两个方法都是由使用了该协议(不是实现了该协议)的类调用,调用的大致方法如下:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.view.backgroundColor = [UIColor whiteColor];
    
        UILabel* userLabel = [[UILabel alloc] init];
        userLabel.frame = CGRectMake(40, 200, 200, 30);
        // 设置了代理
        if ([_delegate respondsToSelector:@selector(userId)])
        {
            userLabel.text = [_delegate userId];
        }
        else
        {
            userLabel.text = @"Delegate not set";
        }
    
        /** 中间代码略 */
    
        // 更新对应代理的头像
        if ([_delegate respondsToSelector:@selector(userId)])
        {
            [_delegate setPortraitPath:imagePath];
        }
    }

    上述代码中使用方法respondsToSelector是查看是否实现了该方法,需要注意的是,这里调用的两个方法都是在实现了代理协议的类里面实现的,而不是当前类实现。需要注意用户信息类要有属性或者变量类型为id<UserInfoDelegate>的,如下所示:

    @interface UserInfo : UIViewController
    
    @property (nonatomic, strong) id<UserInfoDelegate> delegate;
    
    @end
  • 实现代理协议的类是主页面,实现协议就好了
    #pragma 实现协议UserInfoDelegate
    // 当前视图的值传值给对方
    - (NSString*)userId
    {
        return _userText.text;
    }
    // 对方视图的值传值到本类
    - (void) setPortraitPath:(NSString*)portrait
    {
        if (portrait == nil)
        {
            portrait = [[NSBundle mainBundle] pathForResource:@"boy0" ofType:@"png"];
        }
        // 设置头像
        _portraitView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:portrait]];
    }

    然后在转入子页面的时候,设置子页面的代理为当前实例,如此完成了整个部分的参数传值过程。

    - (void)goUser
    {
        UserInfo* user = [[UserInfo alloc] init];
        // 设置代理
        user.delegate = self;
        [self.navigationController pushViewController:user animated:YES];
    }
  • 这样当主页面输入完用户ID后,转到子页面的viewDidLoad方法,由于该方法所在的类拥有设置了用户信息代理(UserInfoDelegate)方,所以可直接使用协议的方法。于是先是通过调用协议的方法userId拿到当前的用户id值,然后根据id查找获取用户id对应的信息,同时在最后通过代理的setPortraitPath:方法向实现代理的对象返回头像路径值。

主要代码

用户信息视图控制类头文件

//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import <UIKit/UIKit.h>

@protocol UserInfoDelegate <NSObject>

@required
/**
 *  获取用户Id
 *
 *  @return 用户ID
 */
- (NSString*)userId;

@optional
/**
 *  默认头像
 */
- (void) setPortraitPath:(NSString*)portrait;

@end

@interface UserInfo : UIViewController

@property (nonatomic, strong) id<UserInfoDelegate> delegate;

@end

用户信息视图控制类实现文件

//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "UserInfo.h"

@implementation UserInfo

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    UILabel* userLabel = [[UILabel alloc] init];
    userLabel.frame = CGRectMake(40, 200, 200, 30);
    // 设置了代理
    if ([_delegate respondsToSelector:@selector(userId)])
    {
        userLabel.text = [_delegate userId];
    }
    else
    {
        userLabel.text = @"Delegate not set";
    }
    userLabel.layer.borderWidth = 1;
    userLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:userLabel];

    UILabel* nameLabel = [[UILabel alloc] init];
    nameLabel.frame = CGRectMake(40, 240, 200, 30);
    nameLabel.layer.borderWidth = 1;
    nameLabel.textAlignment = NSTextAlignmentCenter;
    nameLabel.text = [NSString stringWithFormat:@"name_%d", arc4random()];
    [self.view addSubview:nameLabel];

    UILabel* stateLabel = [[UILabel alloc] init];
    stateLabel.frame = CGRectMake(40, 280, 200, 30);
    stateLabel.layer.borderWidth = 1;
    stateLabel.text = @"该家伙太懒了,什么都没有留下。请邀请ta更新....";
    // 高度自适应
    stateLabel.numberOfLines = 0;
    [stateLabel sizeToFit];
    [self.view addSubview:stateLabel];

    UIImageView* portrait = [[UIImageView alloc] init];
    portrait.frame = CGRectMake(100, 80, 100, 100);
    portrait.layer.borderWidth = 1;
    NSString* imagePath = [[NSBundle mainBundle] pathForResource:userLabel.text ofType:@"png"];
    if(imagePath == nil)
    {
        imagePath = [[NSBundle mainBundle] pathForResource:@"boy3" ofType:@"png"];
        userLabel.text = @"user not exist";
    }
    portrait.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath]];
    portrait.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:portrait];

    // 更新对应代理的头像
    if ([_delegate respondsToSelector:@selector(userId)])
    {
        [_delegate setPortraitPath:imagePath];
    }

}

@end

主页面视图控制类

//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) UIImageView* portraitView;
@property (nonatomic, strong) UITextField* userText;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];
    [super.navigationController setNavigationBarHidden:YES animated:TRUE];
    //[super.navigationController setToolbarHidden:YES animated:TRUE];

    _portraitView = [[UIImageView alloc] init];
    _portraitView.frame = CGRectMake(100, 40, 150, 150);
    [self.view addSubview:_portraitView];

    UILabel* userLabel = [[UILabel alloc] init];
    userLabel.frame = CGRectMake(40, 200, 60, 30);
    userLabel.text = @"用户ID";
    [self.view addSubview:userLabel];

    _userText = [[UITextField alloc] init];
    _userText.frame = CGRectMake(100, 200, 200, 30);
    _userText.placeholder = @"请输入用户ID";
    _userText.returnKeyType = UIReturnKeyGo;
    _userText.layer.borderWidth = 1;
    [_userText addTarget:self action:@selector(goUser) forControlEvents:UIControlEventEditingDidEndOnExit];
    [self.view addSubview:_userText];

    _portraitView = [[UIImageView alloc] init];
    _portraitView.frame = CGRectMake(100, 80, 100, 100);
    _portraitView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:_portraitView];

    [self setPortraitPath:nil];
}

- (void)goUser
{
    UserInfo* user = [[UserInfo alloc] init];
    // 设置代理
    user.delegate = self;
    [self.navigationController pushViewController:user animated:YES];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void) viewWillAppear:(BOOL)animated
{
    //  隐藏导航栏
    [super.navigationController setNavigationBarHidden:YES animated:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    //  显示导航栏
    [super.navigationController setNavigationBarHidden:NO animated:animated];
}

#pragma 实现协议UserInfoDelegate
// 当前视图的值传值给对方
- (NSString*)userId
{
    return _userText.text;
}
// 对方视图的值传值到本类
- (void) setPortraitPath:(NSString*)portrait
{
    if (portrait == nil)
    {
        portrait = [[NSBundle mainBundle] pathForResource:@"boy0" ofType:@"png"];
    }
    // 设置头像
    _portraitView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:portrait]];
}

@end

项目地址

时间: 2024-11-08 19:25:23

代理传值-不同类之间参数传递的相关文章

iOS中多视图的传值 属性传值和代理传值

首先创建两个类 ,FirstViewController和SecondViewController,都继承于UIViewController 1 #import "AppDelegate.h" 2 #import "FirstViewController.h" 3 4 @interface AppDelegate () 5 6 @end 7 8 @implementation AppDelegate 9 10 11 - (BOOL)application:(UIAp

浅谈MVC页面之间参数传递

关于MVC页面之间的传值,有多种方式,下面,我们就Html.RenderAction 方式 和 Html.RenderPartial 方式 来给大家分享一下有什么不同. 一.Html.RenderAction 方式页面之间传递参数的方式: Html.RenderAction 方式 是访问的另一页面的Controller,并将参数传入另一页面的Controller中相应的Action中的参数中. 例如:我有这么一个Controller和Action(是一个部分视图的) 1 public class

【iOS】代理传值与块代码传值

主线程与子线程常常须要进行数据的传递.不同的类之间,不同的控制器之间都须要. 并且常常须要监听一个动作的完毕.而后才去做对应事件. (代理是一对一的关系). 一.代理传值 代理是一种设计模式. iOS中用的许多.能够通过自己定义代理来进行传值. 參见我的这篇文章 http://blog.csdn.net/xn4545945/article/details/31036523 在iOS中.托付方与被托付方都要实现3个步骤.(见代码凝视) 以下代码:模拟下载完毕后须要更新UI. 用代理来传值. XNU

iOS 代理传值(逆传)

休息够了,该写点东西了,前一段时间感冒,发烧,扁桃体发炎,发烧,扁桃体再次发炎,再次发烧,够够的了,进入正题,这次主题是通过代理来实现传值,是逆传,就是反方向传值(废话),准备工作的是,有两个控制器,每个控制器上有两个控件,一个是Button(用来实现控制器之间的跳转),一个是Label(用来展示要传递的值和传递过来的值),代理传值很实用,很多时候用代理解耦,不过代码量也不少: 基本原理:有控制器A,控制器B,代理C,当B快要死的时候找了代理C,说:我快死了,你把我这点遗产给A送过去,我是没机会

iOS--页面间的代理传值(属性、代理(委托)、代码块、单例、通知)

(一)属性传值 第二个界面中的lable显示第一个界面textField中的文本 首先我们建立一个RootViewControllers和一个DetailViewControllers,在DetailViewControllers中声明一个textString属性,用于接收传过来的字符串, (三)代理传值 RootViewControllers页面push到DetailViewControllers页面,如果DetailViewControllers页面的信息想回传(回调)到RootViewCo

iOS 页面间传值 之 属性传值,代理传值

手机 APP 运行,不同页面间传值是必不可少,传值的方式有很多(方法传值,属性传值,代理传值,单例传值) ,这里主要总结下属性传值和代理传值. 属性传值:属性传值是最简单,也是最常见的一种传值方式,但其具有局限性(一般用于将第一个页面的值传递到第二个页面,但无法从第二个页面传到第一个页面), 向SecondViewController传值:SecondViewController 设置属性 sendMessage 1 - (void)rightButtonAction:(UIBarButtonI

属性传值和代理传值的步骤

//属性传值:最常用的传值方式 /** * 操作过程: 1.在第二个页面.h文件中书写属性 (设置那个传值属性) 2.就在第一个页面创建第二页控制器的方法里面,进行赋值操作 3.适用性(局限性): 仅仅适用于第一个页面传值到下一个页面 */ /** * 代理传值 操作过程 1.在第二级控制器.h文件中,设置非正式协议(方法必须带参数) 2.在第二级控制器.h文件中写属性 3.在第二级控制器.m文件中,利用代理属性,去调用协议里面的方法(同时把参数传出来) 4.在第一级控制器中遵守协议 5.在第一

activity之间参数传递&amp;&amp;获取activity返回值&amp;&amp;activity生命周期

Activity之间参数传递 A activity想将参数传给B activity时可以利用Intent将消息带过去 Intent intent = new Intent(this,BActivity.class); intent.putExtra("xxxx", "xxxx"); 数据量多的话可以使用 Bundle bundle = new Bundle(); intent.putExtras(bundle); 获取activity返回值 A activity调用

IOS传值--代理传值,block传值,NSNotificationCenter传值

一:利用代理传值,就是利用代理进行通信. 接口文件: #import <Foundation/Foundation.h> @protocol Cdelegate <NSObject> -(void)change:(NSString *)name; @end .h文件 @interface ViewController : UIViewController<Cdelegate> .m文件 - (IBAction)pushBB:(id)sender { BViewContr