Objective-C的NSNotification和Block传递值

458 阅读16分钟

通知

在IOS中,主要有广播通知(broadcast notification)、本地通知(local notification)和推送通知(push notification),事实上,除了名字相似,广播通知和其它两个通知完全不同,广播通知是Cocoa Touch框架中实现观察者模式的一种机制,它可以在一个应用内部的多个对象之间发送消息本地通知和推送通知中的“通知”是给用户一种提示,它的提示方式有警告对话框、发出声音、震动和在应用图标上显示数字等。在计划事件达到时,本地通知由本地IOS发出。推动通知由第三方程序发送给苹果的运程服务器,再由远程服务器推送给IOS的特定应用

广播通知(broadcast notification)

通知机制是iOS开发中观察者模式的具体应用机制中的一种,以“一对多”的方式在不同类的对象之间通信,在通知机制中对某个通知感兴趣的所有对象都可以成为接收者,也就是常说的页面之间的传值。当然它不仅仅只有这一种应用场景,还有一种常用场景是用来控制一些属性或者控件,使得这些属性或控件在不同情况下发生响应的变化。

NSNotification - 通知信息容器对象

一个通过通知中心向所有注册观察者广播信息的容器对象。通知包含一个名称、一个对象和一个可选的字典,并通过NSNotificationCenter或NSDistributedNotificationCenter的实例广播给它。名称是标识通知的标记。对象是通知的发布者想要发送给该通知的观察者的任何对象(通常是发布通知的对象)。字典存储其他相关对象(如果有的话)。NSNotification对象是不可变的。通常情况不直接创建自己的NSNotification通知对象,而是调用NSNotificationCenter的postNotificationName:object:和postNotificationName:object:userInfo:方法。

常用属性
@property (readonly, copy) NSNotificationName name;

属性描述通知的名称。通常可以使用此属性来确定在收到通知时要处理的通知类型。

@property (nullable, readonly, retain) id object;

属性描述与通知关联的对象。通常是发布此通知的对象。可能是nil。

@property (nullable, readonly, copy) NSDictionary *userInfo;

属性描述与通知关联的用户信息字典。可能是nil。用户信息字典存储接收通知的对象可能使用的任何其他对象。

常用函数
- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;

函数描述 : 使用指定的名称、对象和用户信息初始化通知。

参数 :

name : 通知的名称。不能为nil。

object : 通知的对象。

userInfo : 用于通知的用户信息字典。可能是nil。

+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;

函数描述 : 返回具有指定名称和对象的通知对象。

参数 :

aName : 通知的名称。不能是nil。

anObject : 通知的对象。

+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

函数描述 : 返回具有指定名称、对象和用户信息的通知对象。

参数 :

aName : 通知的名称。不能是nil。

anObject : 通知的对象。

aUserInfo : 通知的用户信息字典。可能是nil。

NSNotificationCenter - 通知中心

一种通知分发机制,允许向注册的观察者广播信息。对象向通知中心注册以使用addObserver:selector:name:object:或addObserverForName:object:queue:usingBlock: 方法来接收通知(NSNotification Objects)。当对象将自己添加为观察者时,它指定应该接收哪些通知。因此,一个对象可能多次调用将自己添加为观察者的方法,以便将自己注册为多个不同通知的观察者。NSNotificationCenter是单例模式

每个运行的应用程序都有一个defaultCenter通知中心,您可以创建新的通知中心来组织特定上下文中的通信

通知中心只能在单个程序中发送通知,如果您想向其他进程发布通知或接收来自其他进程的通知,需要使用NSDistributedNotificationCenter。

常用属性
@property (class, readonly, strong) NSNotificationCenter *defaultCenter;

属性描述应用程序的默认通知中心。发送到应用程序的所有系统通知都将发布到defaultCenter通知中心。也可以在那里发布你自己的通知。如果应用程序广泛使用通知,就可能需要创建并发布到自己的通知中心,而不是只发布到defaultCenter通知中心。当通知发布到通知中心时,通知中心会扫描已注册的观察者列表,这可能会降低应用程序的速度。通过围绕一个或多个通知中心功能性地组织通知,每次发布通知时所做的工作更少,这可以提高整个应用程序的性能。

常用函数
- (void)postNotification:(NSNotification *)notification;

函数描述 : 向通知中心发布给定通知。

参数 :

notification : 要发布的通知。

- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;

函数描述 : 创建具有给定名称和发布通知的对象的通知,并将其发布到通知中心。

参数 :

aName : 通知的名称。

anObject : 发布通知的对象。

- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

函数描述 : 使用给定的名称、发布通知的对象和信息字典创建通知,并将其发布到通知中心。

参数 :

aName : 通知的名称。

anObject : 发布通知的对象。

aUserInfo : 有关通知的可选信息。

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

函数描述向通知中心的调度表中添加一个条目,其中包含一个观察者和一个通知选择器,以及一个可选的通知名称和发送者。如果你的应用目标是iOS 9.0及更高版本或macOS 10.11及更高版本,则不需要在其dealoc方法中注销观察者。否则,需要调用removeObserver:name:object:方法释放传递给此方法的observer。

参数 :

observer : 对象注册为观察者。

aSelector : 选择器,指定接收方发送给观察者以通知其通知发布的消息(收到通知要执行的函数)。aSelector指定的方法必须有且只有一个参数(NSNotification的实例)。

aName : 要为其注册观察者的通知的名称;也就是说,只有具有此名称的通知才会传递给观察者。

anObject : 观察者希望接收其通知的对象;也就是说,只有此发送者发送的通知才会传递给观察者。如果传递nil,通知中心不会使用通知的发送者来决定是否将其传递给观察者。

- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

函数描述向通知中心的调度表添加一个条目,该表包括通知队列和要添加到队列的块,以及可选的通知名称和发送者。如果一个给定的通知触发了多个观察者块,那么这些块都可以相对于其他块并发执行(但是在它们的给定队列或当前线程上)。

参数 :

name : 要为其注册观察者的通知的名称;也就是说,只有具有此名称的通知才用于将块添加到操作队列中。如果传递nil,通知中心不会使用通知的名称来决定是否将块添加到操作队列。

obj : 观察者希望接收其通知的对象;也就是说,只有此发送者发送的通知才会传递给观察者。如果传递nil,通知中心不会使用通知的发送者来决定是否将其传递给观察者。

queue : 应向其中添加块的操作队列。如果传递nil,则块在发布线程上同步运行。

block : 接收到通知时要执行的块。块由通知中心复制,并保留(副本),直到移除观察者注册。并且块接受一个NSNotification参数。

返回值 : 充当观察者的不确定对象。

- (void)removeObserver:(id)observer;

函数描述从通知中心的调度表中删除指定给定观察者的所有条目。如果你的应用程序的目标是iOS 9.0及以后,或macOS 10.11及以后,则不需要在它的dealloc方法中注销观察者。否则,应该在dealloc中调用这个方法或removeObserver:name:object:方法释放观察者或之前任何在addObserverForName:object:queue:usingBlock:或addObserver:selector:name:object: 方法中指定的对象。

参数 :

observer : 要删除的观察者。

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

函数描述从通知中心的调度表中删除匹配的条目。如果你的应用程序的目标是iOS 9.0及以后,或macOS 10.11及以后,则不需要在它的dealloc方法中注销观察者。否则,应该在dealloc中调用这个方法或removeObserver:name:object:方法释放观察者或之前任何在addObserverForName:object:queue:usingBlock:或addObserver:selector:name:object: 方法中指定的对象。

参数 :

observer : 要从调度表中删除的观察者。指定一个观察者以仅删除此观察者在调度表中的条目。

aName : 要从调度表中删除的通知的名称。指定通知名称以仅删除指定此通知名称的条目。当为空时,接收方不使用通知名称作为删除的标准。

anObject : 要从调度表中删除的发送者。指定通知发件人以仅删除指定此发送者的条目。当为空时,接收方不使用通知发送者作为删除的标准。

Block - 匿名函数块

带有自动变量(局部变量)的匿名函数。是对C语言不允许存在这样匿名函数的扩展。block本质上是一个封装了函数调用以及函数调用环境的OC对象。

Block捕获变量示例

示例1:

int age=10;
void (^Block)(void) = ^{
    NSLog(@"age:%d",age);
};
age = 20;
Block();

输出结果:age:10 。

原因:创建Block的时候,已经把age的值存储在里面了。

示例2:

auto int age = 10;
static int num = 25;
void (^Block)(void) = ^{
    NSLog(@"age:%d,num:%d",age,num);
};
age = 20;
num = 11;
Block();

输出结果 : age:10,num:11 。

原因 : auto变量Block访问方式是值传递,static变量Block访问方式是指针传递。

造成Block对auto和static变量捕获差异的原因 : auto自动变量可能会销毁的,内存可能会消失,不采用指针访问;static变量一直保存在内存中,指针访问即可。

归纳 : Block变量捕获机制

1915113-b684175082c9a822.png

Block分类

  • GlobalBlock : 位于全局区,在Block内部不使用外部变量,或者只使用静态变量和全局变量。

  • MallocBlock : 位于堆区,在Block内部使用局部变量或者OC属性,并且赋值给强引用或者Copy修饰的变量。

  • StackBlock : 位于栈区,与MallocBlock一样,可以在内部使用局部变量或者OC属性,但是不能赋值给强引用或者Copy修饰的变量。

Block的循环引用

一段循环引用的代码 :

截屏2020-09-24下午11.14.27.png

一般对于循环引用,Xcode会给出Capturing 'HomePageVC' strongly in this block is likely to lead to a retain cycle(在此块中强烈捕获“HomePageVC”很可能导致保留周期)提示。

对象类型的auto变量的捕获可以归纳为

  • 如果Block在栈空间,不管外部变量是强引用还是弱引用,block都会弱引用访问对象。
  • 如果Block在堆空间,如果外部强引用,block内部也是强引用;如果外部弱引用,block内部也是弱引用。

处理这种简单的循环引用:

截屏2020-09-24下午11.30.13.png

传值实例Demo :


TransmitValueTestLoginController.h文件

#import <UIKit/UIKit.h>

@interface TransmitValueTestLoginController : UIViewController

@end

TransmitValueTestLoginController.m文件

#import "TransmitValueTestLoginController.h"
#import "TransmitValueTestRegisterController.h"
#import "TransmitValueTestHomePageController.h"

@interface TransmitValueTestLoginController ()<UITextFieldDelegate>

@property (nonatomic, strong) UITextField *userNameText;//用户名输入框
@property (nonatomic, strong) UITextField *passWordText;//密码输入框
@property (nonatomic, strong) UIButton  *loginBtn;//登录按钮
@property (nonatomic, strong) UIButton *resignBtn;//注册按钮

@end

@implementation TransmitValueTestLoginController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置控制器标题
    self.title = @"登录";
    //设置控制器视图背景颜色
    self.view.backgroundColor = [UIColor yellowColor];
    //初始化用户名输入框
    self.userNameText = [self getTextField:100 leftViewName:@" 用户名:"];
    //初始化密码输入框
    self.passWordText = [self getTextField:CGRectGetMaxY(_userNameText.frame)+20 leftViewName:@" 密码:"];
    //初始化登录按钮
    self.loginBtn = [self buttonInitWith:CGRectMake(self.view.frame.size.width - 20 - 100, CGRectGetMaxY(_passWordText.frame) + 50, 100, 45) withTitle:@"登录"];
    self.loginBtn.backgroundColor=[UIColor redColor];
    //初始化注册按钮
    self.resignBtn=[self buttonInitWith:CGRectMake(20, CGRectGetMaxY(_passWordText.frame)+50, 100, 45) withTitle:@"注册"];
    self.resignBtn.backgroundColor=[UIColor greenColor];
    //接收通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(fun:) name:@"tongzhi" object:nil];
}

///初始化输入框
-(UITextField *)getTextField:(CGFloat )y leftViewName:(NSString *)name{
    //初始化输入框
    UITextField *  textField=[[UITextField alloc]initWithFrame:CGRectMake(20, y, self.view.frame.size.width - 40, 45)];
    //设置输入框边框的宽度
    textField.layer.borderWidth = 1.0f;
    //输入的文字颜色
    textField.textColor = [UIColor greenColor];
    //设置输入框代理
    textField.delegate = self;
    //输入框左视图始终显示
    textField.leftViewMode = UITextFieldViewModeAlways;
    //设置输入框提示文本及提示文本颜色
    textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入" attributes:@{NSForegroundColorAttributeName : [UIColor greenColor]}];
    //透明效果
    [textField setBackgroundColor:[UIColor clearColor]];
    //将输入框添加到当前控制器视图
    [self.view addSubview:textField];
    
    //初始化标签
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 45)];
    //设置标签文本
    label.text = name;
    //设置标签文本对齐方式
    label.textAlignment = NSTextAlignmentCenter;
    //设置标签文本字体大小
    label.font = [UIFont systemFontOfSize:14];
    //设置标签文本的颜色
    label.textColor = [UIColor greenColor];
    //文字自动适应标签宽度,当文字宽大于文本控件的宽时才会调整
    label.adjustsFontSizeToFitWidth = YES;
    //设置输入框的左视图
    textField.leftView = label;
    
    return textField;
}

///初始化按钮
- (UIButton *)buttonInitWith:(CGRect)frame withTitle:(NSString *)name{
    //初始化按钮
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    //设置按钮位置
    button.frame = frame;
    //设置按钮标题
    [button setTitle:name forState:UIControlStateNormal];
    //设置按钮标题颜色
    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    //按钮添加点击事件
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    //将按钮添加到控制器视图
    [self.view addSubview:button];
    //返回初始化的按钮
    return button;
}

///按钮点击事件
- (void)buttonClick:(UIButton *)button{
    //输入框放弃第一响应对象
    [self textResignFirstResponder];
    //注册按钮点击事件
    if ([button.titleLabel.text isEqualToString:@"注册"]) {
        NSLog(@"注册");
        TransmitValueTestRegisterController *resignVC = [[TransmitValueTestRegisterController alloc]init];
        [self.navigationController pushViewController:resignVC animated:YES];
    }
    //登录按钮点击事件
    if ([button.titleLabel.text isEqualToString:@"登录"]) {
        NSLog(@"登录");
        TransmitValueTestHomePageController *HomePageVC = [[TransmitValueTestHomePageController alloc]init];
        //属性传值
        HomePageVC.userName = self.userNameText.text;
        HomePageVC.passWord = self.passWordText.text;
        [self.navigationController pushViewController:HomePageVC animated:YES];
        //Block回调
        HomePageVC.MyBlock = ^(NSString *userName,NSString *passWord){
            self.userNameText.text = userName;
            self.passWordText.text = passWord;
        };
    }
}

///输入框放弃第一响应对象
- (void)textResignFirstResponder{
    [_userNameText resignFirstResponder];
    [_passWordText resignFirstResponder];
}

///手指按下事件
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //输入框放弃第一响应对象
    [self textResignFirstResponder];
}

#pragma mark UITextFieldDelegate
///点击return键
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    //输入框放弃第一响应对象
    [self textResignFirstResponder];
    return YES;
}

///通知执行的方法
-(void)fun:(NSNotification *)notification{
    //取出通知传递参数的字典
    NSDictionary *dic = notification.userInfo;
    //设置用户名输入框内容
    self.userNameText.text = [dic objectForKey:@"userName"];
    //设置密码输入框内容
    self.passWordText.text = [dic objectForKey:@"passWord"];
}


@end

TransmitValueTestRegisterController.h文件

#import <UIKit/UIKit.h>

@interface TransmitValueTestRegisterController : UIViewController

@end

TransmitValueTestRegisterController.m文件

#import "TransmitValueTestRegisterController.h"

@interface TransmitValueTestRegisterController ()<UITextFieldDelegate>

@property (nonatomic, strong) UITextField *userNameText;//用户名输入框
@property (nonatomic, strong) UITextField *passWordText;//密码输入框
@property (nonatomic, strong) UIButton  *loginBtn;//登录按钮
@property (nonatomic, strong) NSDictionary *dictionary;//传递通知参数时使用的字典

@end

@implementation TransmitValueTestRegisterController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置控制器标题
    self.title = @"注册";
    //设置控制视图背景颜色
    self.view.backgroundColor = [UIColor greenColor];
    //初始化用户名输入框
    self.userNameText = [self getTextField:100 leftViewName:@" 用户名:"];
    //初始化密码输入框
    self.passWordText = [self getTextField:CGRectGetMaxY(_userNameText.frame)+20 leftViewName:@" 密码:"];
    //初始化登录按钮
    self.loginBtn = [self buttonInitWith:CGRectMake((self.view.frame.size.width - 50) /2,CGRectGetMaxY(self.passWordText.frame) + 50 , 100, 45) withTitle:@"登录"];
    self.loginBtn.backgroundColor=[UIColor redColor];
}

///初始化文本输入框
-(UITextField *)getTextField:(CGFloat )y leftViewName:(NSString *)name{
    //初始化输入框
    UITextField *  textField=[[UITextField alloc]initWithFrame:CGRectMake(20, y, self.view.frame.size.width - 40, 45)];
    //设置输入框边框的宽度
    textField.layer.borderWidth = 1.0f;
    //输入的文字颜色
    textField.textColor = [UIColor redColor];
    //设置输入框代理
    textField.delegate = self;
    //输入框左视图始终显示
    textField.leftViewMode = UITextFieldViewModeAlways;
    //设置输入框提示文本及提示文本颜色
    textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入" attributes:@{NSForegroundColorAttributeName : [UIColor redColor]}];
    //透明效果
    [textField setBackgroundColor:[UIColor clearColor]];
    //将输入框添加到当前控制器视图
    [self.view addSubview:textField];
    
    //初始化标签
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 45)];
    //设置标签文本
    label.text = name;
    //设置标签文本对齐方式
    label.textAlignment = NSTextAlignmentCenter;
    //设置标签文本字体大小
    label.font = [UIFont systemFontOfSize:14];
    //设置标签文本颜色
    label.textColor = [UIColor redColor];
    //文字自动适应标签宽度,当文字宽大于文本控件的宽时才会调整
    label.adjustsFontSizeToFitWidth = YES;
    //设置输入框的左视图
    textField.leftView = label;
    
    return textField;
}

///初始化按钮
- (UIButton *)buttonInitWith:(CGRect)frame withTitle:(NSString *)name{
    //初始化按钮
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    //设置按钮位置
    button.frame = frame;
    //设置按钮标题
    [button setTitle:name forState:UIControlStateNormal];
    //设置按钮标题颜色
    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    //按钮添加点击事件
    [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
    //添加按钮到控制器视图
    [self.view addSubview:button];
    //返回按钮
    return button;
}

- (void)buttonClick{
    //输入框放弃第一响应对象
    [self textResignFirstResponder];
    //设置通知传递值时使用的字典
    self.dictionary = @{@"userName":self.userNameText.text,
                        @"passWord":self.passWordText.text};
    //发送通知
    [[NSNotificationCenter defaultCenter]postNotificationName:@"tongzhi" object:nil userInfo:self.dictionary];
    //关闭控制器
    [self.navigationController popViewControllerAnimated:YES];
}

///输入框放弃第一响应对象
- (void)textResignFirstResponder{
    [_userNameText resignFirstResponder];
    [_passWordText resignFirstResponder];
}

@end

TransmitValueTestHomePageController.h文件

#import <UIKit/UIKit.h>


@interface TransmitValueTestHomePageController : UIViewController
//传递用户名的属性
@property(nonatomic,copy) NSString *userName;
//传递密码的属性
@property(nonatomic,copy) NSString *passWord;
//定义一个MyBlock属性
@property (nonatomic,copy)void(^MyBlock)(NSString *userName,NSString *passWord);

@end

TransmitValueTestHomePageController.m文件

#import "TransmitValueTestHomePageController.h"

@interface TransmitValueTestHomePageController ()<UITextFieldDelegate>

@property(nonatomic, strong) UITextField *userNameText;//用户名输入框
@property(nonatomic, strong) UITextField *passWordText;//密码输入框
@property (nonatomic, strong) UIButton  *returnBtn;//登录按钮

@end

@implementation TransmitValueTestHomePageController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置控制器标题
    self.title = @"首页";
    //设置控制器视图背景颜色
    self.view.backgroundColor = [UIColor redColor];
    //初始化用户名输入框
    self.userNameText=[self getTextField:100 leftViewName:@" 用户名:"];
    //设置用户名输入框文本
    self.userNameText.text = self.userName;
    //初始化密码输入框
    self.passWordText=[self getTextField:CGRectGetMaxY(_userNameText.frame)+20 leftViewName:@" 密码:"];
    //设置密码输入框文本
    self.passWordText.text = self.passWord;
    //初始化返回按钮
    self.returnBtn = [self buttonInitWith:CGRectMake((self.view.frame.size.width - 50) /2,CGRectGetMaxY(self.passWordText.frame) + 50 , 100, 45) withTitle:@"返回"];
    self.returnBtn.backgroundColor = [UIColor purpleColor];
}

///初始化文本输入框
-(UITextField *)getTextField:(CGFloat )y leftViewName:(NSString *)name{
    //初始化输入框
    UITextField *  textField=[[UITextField alloc]initWithFrame:CGRectMake(20, y, self.view.frame.size.width - 40, 45)];
    //设置输入框边框的宽度
    textField.layer.borderWidth = 1.0f;
    //输入的文字颜色
    textField.textColor = [UIColor yellowColor];
    //设置输入框代理
    textField.delegate = self;
    //输入框左视图始终显示
    textField.leftViewMode = UITextFieldViewModeAlways;
    //设置输入框提示文本及提示文本颜色
    textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入" attributes:@{NSForegroundColorAttributeName : [UIColor yellowColor]}];
    //透明效果
    [textField setBackgroundColor:[UIColor clearColor]];
    [self.view addSubview:textField];//将输入框添加到当前控制器视图
    //初始化标签
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 45)];
    //设置标签文本
    label.text = name;
    //设置标签文本对齐方式
    label.textAlignment = NSTextAlignmentCenter;
    //设置标签文本字体大小
    label.font = [UIFont systemFontOfSize:14];
    //设置标签文本颜色
    label.textColor = [UIColor yellowColor];
    //文字自动适应标签宽度,当文字宽大于文本控件的宽时才会调整
    label.adjustsFontSizeToFitWidth = YES;
    //设置输入框的左视图
    textField.leftView = label;
    
    return textField;
}

///初始化按钮
- (UIButton *)buttonInitWith:(CGRect)frame withTitle:(NSString *)name{
    //初始化按钮
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    //设置按钮位置
    button.frame = frame;
    //设置按钮标题
    [button setTitle:name forState:UIControlStateNormal];
    //设置按钮标题颜色
    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    //按钮添加点击事件
    [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
    //添加按钮到视图控制器
    [self.view addSubview:button];
    //返回按钮
    return button;
}

///按钮点击事件
-(void)buttonClick{
    //Block传值
    self.MyBlock(self.userNameText.text, self.passWordText.text);
    [self.navigationController popViewControllerAnimated:YES];
}
@end

简单的运行效果:

Jietu20200920-224808.gif

《整理自IOS开发指南、逻辑教育、梦蕊dream