iOS界面间传值

知识点大纲

(1) 什么是界面传值?

(2) 正向传值

(3) 代理传值

(4) 单例传值

(5) 通知传值

(6) 代码块传值

1.什么是界面传值?

绝大多数应用都是由多个界面构成的,需要在界面之间传输数据,这就是界面传值。

2. 正向传值

实例:登陆界面创建主界面,登陆界面的用户名传递到主界面

分析:A界面创建B界面,A界面的值传递到B界面

如何实现?

》在B界面中添加属性,用来保存用户名

@interface MainViewController : UIViewController

// 定义了可以接受其他界面传过来的值

  

 @property (nonatomic,copy) NSString *userName;

 @end

》A界面中

    // 主界面

   

 MainViewController *mainVC = [[MainViewController alloc] init];

    // 注意:界面切换前传值

   

 mainVC.userName = @"hehe";

    // 跳转

   

 [self presentViewController:mainVC animated:YES completion:nil];

》B界面中

    //显示传过来的用户名

   

 UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 200, 30)];

    nameLabel.text = [NSString stringWithFormat:@"用户名是: %@",_username];

    [self.view addSubview:nameLabel];

3.反向传值(代理)

代理传值六步走:

// A界面创建B界面, B把值(颜色)传回给A界面

    MainViewController                                    ConfigViewController

 

(1) 第一步,制定协议(哪里通知代理)

//因为是ConfigViewController其他界面发送消息

//  1. 告诉其他界面我要给你发送什么消息

//  2. 确保其他实现了消息对应的方法

// 声明协议和协议方法

@protocol ConfigViewControllerDelegate <NSObject>

// 最好以类型开头+方法名

// 在遵守协议的其他类实现方法(即只声明不实现)

-(void)conifgViewControllerWithBackgroundColor:(UIColor *)color;

@end
 
@interface ConfigViewController : UIViewController

(2) 第二步,定义属性

// 作用: 保存主界面的指针

// 为什么保存, 最后给主界面发送消息修改字体

// 细节1: weak 确保不会循环引用

// 细节2: id 如果是id, 能传入任意界面了

// 细节3: 遵守协议意味着可以任意对象

@property (nonatomic,weak) id<ConfigViewControllerDelegate> delegate;


@end
 

(3) 第三步,通知代理

// 通知代理(其实就是调用方法)

// 判断是否实现了代理方法

if ([self.delegate respondsToSelector:@selector(changeFontSize:)]) {

    [self.delegate changeFontSize:fontTextField.text.intValue]; 

}

(4) 第四步,遵守协议 

@interface MainViewController () <ConfigViewControllerDelegate>
 

 //切换到配置界面

    ConfigViewController *configVC = [[ConfigViewController alloc] init];

    (5) 第五步,设置成为代理

    // 作用: 把当前界面的指针传到configVC中

    // 为啥: 希望配置界面中背景颜色改变通知主界面

    configVC.delegate = self;

    

    [self presentViewController: configVC animated:YES completion:nil];
 

(6) 第六步,实现代理方法(具体方法的实现)

- (void)conifgViewControllerWithBackgroundColor:(UIColor *)color{

    NSLog(@"实现的代理方法");

    self.view.backgroundColor = color;

}
 

 

》在声明代理属性时

// 不能使用strong,避免VC调用sVC,然后sVC再调用VC形成循环引用,内存无法释放

@property (nonatomic,weak) id<SecondViewControllerDelegate> delegate;

(4) 单例传值(1对N)

需求:A(登陆)->B->C->D->E->F(用户信息)

需要A中的数据在F界面中显示;

需要在每个界面中都显示“今天脱口秀”;

解决:使用单例传值

/** 懒汉式(真正用到的时候才加载) 饿汉式(程序一启动就加载)

 *  单例模式顾名思义就是只有一个实例,它确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。它经常用来做应用程序级别的共享资源控制。这个模式使用频率非常高,通过一个单例类,可以实现不同view之间的参数传递

 */

实现:

》创建一个单例类DataClass

@interface DataClass : NSObject

 // 定义要使用的属性

  @property (nonatomic,copy) NSString *user;

  @property (nonatomic,strong) NSString *passwd;

  // 类方法

  + (instancetype)shareData;

  @end

// 关键

    // 第一次执行: shareData为空, 会申请一个对象

    // 以后执行: shareData不为空, 直接返回以前创建的对象

static DataClass *shareData = nil;

 

// 表示获取一个共享的实例

    + (instancetype)shareData{

        if (shareData == nil) {

            shareData = [[DataClass alloc] init];

        }

        return shareData;

    }
   // alloc方法内部会调用这个方法

// 最好实现重写这个方法,避免在实例化的时候用到了alloc + init

    + (instancetype)allocWithZone:(struct _NSZone *)zone{

        if (shareData == nil) {

            shareData = [super allocWithZone:zone];

        }

        return shareData;

    }

//要求非常高单例类往往重写

//  alloc,dealloc,retain,release,

//  autorelease,copyWithZone
》存储值

  DataClass *sharData = [DataClass shareData];

    sharData.user = @"单例模式";

    sharData.passwd = @"123321";

》取值

    DataClass *dataShare = [DataClass shareData];

    NSLog(@"%@",dataShare);

(5) 通知传值(1对N)

A - B - C - D - E - F - G(通知A为红色,B界面为蓝色,C界面为黑色…)

 需求: 配置界面要换皮肤(背景颜色),其他界面相应

实现:

》配置界面中,发送换皮肤的通知   

    // 获取系统通知类的单例对象

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    // 发出一个通知

    // 参数Name: 通知的名字

    // 参数object: 要发给那个对象, nil表示不限制对象

    // 参数userInfo: 通知附加的信息, 皮肤颜色传过去

// 原型[center postNotificationName:(NSString *) object:(id) userInfo:(NSDictionary *)];

    [center postNotificationName:@"color" object:nil userInfo:@{@"color":[UIColor magentaColor]];

 

》其他界面获取到通知,切换背景

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    // 获取通知

    // 参数addObserver: 观察者,监听者

    // 参数selector: 获取到通知后的处理方法

    // 参数name: 通知的名字

    // 参数object: 要接受那个对象,nil表示不限制对象

    [center addObserver:self selector:@selector(centerTest:) name:@"color" object:nil];

 

// 注意: 参数类型不是NSNotificationCenter

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

// 获取通知中附加的信息

    NSLog(@"FirstViewController >> %@",notification.userInfo[@"color"]);

 

    self.view.backgroundColor = notification.userInfo[@"color"];

}

给不同界面发送通知

[center postNotificationName:@"button" object:nil userInfo:@{@"button":@"yes",@"fVC":[UIColor brownColor],@"sVC":[UIColor cyanColor],@"tVC":[UIColor orangeColor]}];

(6) 代码块传值

1> 如何定义block变量(block是一种数据类型)

 int (^sumBlock)(int, int);

 void (^myBlock)();

代码块传值三步走:

// A界面创建B界面, B界面把背景颜色传回给A界面

实现:

》第一步

声明代码块变量,并声明set方法

@property (nonatomic,copy) void (^changeBackColor)(UIColor *color);

- (void)setChangeBackColor:(void (^)(UIColor *))changeBackColor;
三小步:

> 模拟要实现的功能方法

    // 模拟要实现的功能
 - (void)changeBackColor:(UIColor *)color{

            self.view.backgroundColor = color;

    }

  > 将方法转为函数 

// 将方法转为函数

        void changeBackColor(UIColor *color){

            self.view.backgroundColor = color;

        }

  > 将函数转为代码块

// 将函数转为代码块

        void (^changeBackColor)(UIColor *color) = ^(UIColor *color){

            self.view.backgroundColor = color;

        };

 

》第二步

代码块的调用

__weak typeof(self) weakSelf = self;

    // 代码块的调用,设置背景

    if (weakSelf.changeBackColor) { // 判断代码块是否为空

        NSArray *colors = @[[UIColor yellowColor],

                            [UIColor blueColor],

                            [UIColor greenColor]];

        // 代码块的调用

// 产生随机数arc4random()

        weakSelf.changeBackColor(colors[arc4random()%3]);

    }

 

》第三步

     设置代码块中具体操作

// 把代码块作为参数传递

    [mVC setChangeBackColor:^(UIColor *color) { 

 

        self.view.backgroundColor = color;

    }];

    /**

     1、默认strong,可选weak。strong下不管成员变量还是property,每次使用指针指向一个对象,等于自动调用retain(), 并对旧对象调用release(),所以设为nil等于release。

     2、只要某个对象被任一strong指针指向,那么它将不会被销毁,否则立即释放,不用等runloop结束。所有strong指针变量不需要在dealloc中手动设为nil,ios会自动处理,debug可以看到全部被置为nil,最先声明的变量最后调用dealloc释放。

     

     3、官方建议IBOutlet加上__weak,实际上不用加也会自动释放;

     

     4、优先使用私有成员变量,除非需要公开属性才用property。

     

     5、避免循环引用,否则手动设置nil释放。

     

     6、block方法常用声明:@property (copy) void(^MyBlock)(void); 如果超出当前作用域之后仍然继续使用block,那么最好使用copy关键字,拷贝到堆区,防止栈区变量销毁。

     

     7、创建block匿名函数之前一般需要对self进行weak化,否则造成循环引用无法释放controller:

          __weak typeof(self) weakSelf = self;

     引用实例变量也会造成self的强引用,实例变量要用weakSelf->实例变量 的方式来访问

     */

原文地址:https://www.cnblogs.com/vkSwift/p/12916484.html