您的位置:首页 > 移动开发 > IOS开发

iOS编程——OC viewController 传值常用方法Delegate和Block的使用

2015-08-24 13:05 639 查看
写了个例子,简单介绍了下Delegate和Block的使用,注意点都在注释里,直接上代码了:

1.FirstViewController.h:

#import <UIKit/UIKit.h>

@interface FirstViewController : UIViewController

@end


FirstViewController.m:

#import "FirstViewController.h"
#import "SecondViewController.h"

@interface FirstViewController() <SecondViewDelegate>

@property (nonatomic, strong) UITextField   *textField;

@property (nonatomic, strong) UIButton      *button;

@end

@implementation FirstViewController

- (void) viewDidLoad {
[super viewDidLoad];
self.title = @"First";
self.view.backgroundColor = [UIColor whiteColor];

CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;

//通过Delegate和Block来改变textField的text
self.textField = [[UITextField alloc] initWithFrame:CGRectMake((screenWidth - 300) / 2, 100, 300, 40)];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.textField.text = @"oldValue";
[self.view addSubview:self.textField];

//跳转button
self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.button.frame = CGRectMake((screenWidth - 300) / 2, 200, 300, 40);
[self.button setTitle:@"PushSecondViewController" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.button setBackgroundColor:[UIColor greenColor]];
[self.button addTarget:self action:@selector(pushViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
}

- (void) pushViewController {
SecondViewController *secondViewController = [[SecondViewController alloc] init];
//使用delegate
secondViewController.delegate = self;

//使用__weak(非arc使用__block)来避免循环引用
__weak SecondViewController *weakSecondViewController = secondViewController;

//使用block
secondViewController.changeBlock = ^(NSString *newValue) {
if (newValue) {
self.textField.text = newValue;
}

//直接调用会报循环引用的警告: Capturing 'secondViewController' strongly in this block is likely to lead to a retain cycle
//        [secondViewController testRetainCyclesInSecondView];

//解决循环引用
[weakSecondViewController testRetainCyclesInSecondView];
};

[self.navigationController pushViewController:secondViewController animated:YES];

//置为nil,当返回时secondViewController会调用dealloc方法
secondViewController = nil;
}

#pragma mark ==== SecondViewDelegate Method ====
//实现secondViewController协议
- (void) changeFirstViewValue:(NSString *)newValue {
if (newValue) {
self.textField.text = newValue;
}
}

@end


2.SecondViewController.h:

#import <UIKit/UIKit.h>

//使用delegate先要声明一个协议
@protocol SecondViewDelegate <NSObject>

- (void) changeFirstViewValue: (NSString *) newValue;

@end

//声明一个Block
typedef void (^ChangeValueBlock) (NSString *);

@interface SecondViewController : UIViewController

//实现协议的一个delegate,通过它指向FirstViewController
@property (nonatomic, weak) id <SecondViewDelegate> delegate;

//声明外部的Block
@property (atomic, copy) ChangeValueBlock changeBlock;

//测试循环引用
- (void) testRetainCyclesInSecondView;

@end


SecondViewController.m:

#import "SecondViewController.h"

@interface SecondViewController()

@property (nonatomic, strong) UIButton      *delegateButton;

@property (nonatomic, strong) UIButton      *blockButton;

@end

@implementation SecondViewController

//没用引用外部变量的block
typedef int (^NoExternalVarBlock) ();

NoExternalVarBlock func() {
return ^{ return 10;};
}

//引用外部变量的block
typedef int (^ExternalVarBlock) ();

ExternalVarBlock func1() {
int i = 10;
return ^{ return i;};
}

- (void) viewDidLoad {
[super viewDidLoad];
self.title = @"Second";
self.view.backgroundColor = [UIColor whiteColor];
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;

//使用Delegate修改textField的text
self.delegateButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.delegateButton.frame = CGRectMake((screenWidth - 300) / 2, 100, 300, 40);
[self.delegateButton setTitle:@"ChangeFistValueWithDelegate" forState:UIControlStateNormal];
[self.delegateButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.delegateButton setBackgroundColor:[UIColor greenColor]];
[self.delegateButton addTarget:self action:@selector(changeValueWithDelegate) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.delegateButton];

//使用Block修改textField的text
self.blockButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.blockButton.frame = CGRectMake((screenWidth - 300) / 2, 200, 300, 40);
[self.blockButton setTitle:@"ChangeFistValueWithBlock" forState:UIControlStateNormal];
[self.blockButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.blockButton setBackgroundColor:[UIColor redColor]];
[self.blockButton addTarget:self action:@selector(changeValueWithBlock) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.blockButton];

//测试Block的初始化内存位置(arc下)
[self test];
}

- (void) test {
//block使用
__block NSInteger oneNum = 10;//不使用__block报错: Variable is not assignable (missing __block type specifier)

NSInteger (^testBlock) (NSInteger) = ^(NSInteger num){
oneNum += num;
return num * num;
};

NSLog(@"%ld",(long)testBlock(10));

//没有引用外部变量的block,无论arc还是marc都是__NSGlobalBlock__,不需要考虑作用域问题。
NoExternalVarBlock nevBlock = func();
NSLog(@"%@",[nevBlock class]);
NSLog(@"%p",nevBlock);

NoExternalVarBlock nevBlock1 = [nevBlock copy];
NSLog(@"%p",nevBlock1);

//引用了外部变量的block,没有copy的话它的作用域只存在函数栈内,类型为__NSStackBlock__,非arc下会报错,arc下自动进行了copy,不会报错。
ExternalVarBlock evBlock = func1();
NSLog(@"%@",[evBlock class]);
NSLog(@"%p",evBlock);

}

- (void) changeValueWithDelegate {
if (self.delegate && [self.delegate respondsToSelector:@selector(changeFirstViewValue:)]) {
//如果FirstViewController设置了代理并且实现了协议,就会进来
[self.delegate changeFirstViewValue:@"newValueWithDelegate"];

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"textField did changed with Delegate.\n Back to see the result." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
alert = nil;
}
}

- (void) changeValueWithBlock {
//使用atomic保证原子性但是并未实现线程安全,在使用时可以先把block赋值给本地变量,这样防止block被别的线程改变,防止因为空值导致的crash
ChangeValueBlock localBlock = self.changeBlock;

if (localBlock) {
localBlock(@"newValueWithBlock");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"textField did changed with Block. Back to see the result." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
alert = nil;
}

//mrc下需要手动retain下block,
//    ChangeValueBlock localBlock = [self.changeBlock retain];
//    if (localBlock) {
//        localBlock(@"newValueWithBlock");
//    }
//    [localBlock release];
}

- (void) testRetainCyclesInSecondView {
NSLog(@"test retain cycles.");
}

- (void) dealloc {
//SecondViewController释放会调用此方法,检查有没有释放。
NSLog(@"SecondViewController dealloc.");
}

@end


3.测试:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
FirstViewController *firstVC = [[FirstViewController alloc] init];

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstVC];
self.window.rootViewController = navigationController;
return YES;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: