iOS Block理解

  以前看到Block觉得也没什么,不就是类似函数的东西,这东西在C#里就是委托,在Java里就是块,有什么稀奇的。但看到一点进阶的内容后,发现这个东西确实有用。

所以做下总结。

一、块的基本用法

块的语法构成:

^[返回值类型](形参1,形参2,...) {

        //执行体

 }

在JS里,函数是可以做为变量的,OC的块也用变量接收,变量的声明语法:

//可以把形参名省略,只保留类型
返回值类型 (^块名) (形参1,形参2,...);

再来看几个例子就懂基本怎么用了:

int main(int argc , char * argv[])
{
    @autoreleasepool{
        // 定义不带参数、无返回值的块
        void (^printString)(void) = ^(void)
        {
            NSLog(@"我正在开始学习Objective-C的块");
        };
        // 使用printString调用块
        printString();
        // 定义带参数、有返回值的块
        double (^hypot)(double , double) =
            ^(double num1, double num2)
        {
            return sqrt(num1 * num1 + num2 * num2);
        };
        // 调用块,并输出块的返回值
        NSLog(@"%g" , hypot(3, 4));
        // 也可以先只定义块变量:定义带参数、无返回值的块
        void (^print)(NSString*);
        // 再将块赋给指定的块变量
        print = ^(NSString* info)
        {
            NSLog(@"info参数为:%@" , info);
        };
        // 调用块
        print(@"树狗狗");
    }
}

还有一点要注意,块可以访问程序局部变量的值,但不能进行修改:

int main(int argc , char * argv[])
{
    @autoreleasepool{
        // 定义局部变量
        int my = 20;
        void (^printVar)(void) = ^(void)
        {
            // 尝试对局部变量赋值,程序将会报错
//            my = 30;           // ①
            // 访问局部变量的值是允许的
            NSLog(@"%d" , my);
        };
        // 再次将my赋值为45
        my = 45;
        // 调用块
        printVar();
    }
}

上在程序尝试修改局部变量,但会报错,而调用块前,把局部变量修改为45后再调用块,这个时候输出的却是:20,因为块定义时会把局部变量的值保存,而不是运行时去读取。

但这却是可以解决的,OC提供了一个_block关键字,用在定义局部变量时,让块里可以等到运行时访问,或者修改都可以。这样用:

int main(int argc , char * argv[])
{
    @autoreleasepool{
        // 定义__block修饰的局部变量
        __block int my = 20;
        void (^printVar)(void) = ^(void)
        {
            // 运行时候访问、获取局部变量的值,此处输出45
            NSLog(@"%d" , my);
            // 尝试对__block局部变量赋值是允许的
            my = 30; // ①
            // 此处输出30
            NSLog(@"%d" , my);
        };
        // 再次将my赋值为45
        my = 45;
        // 调用块
        printVar();
        // 由于块修改了__block局部变量的值,因此下面代码输出30
        NSLog(@"块执行完后,my的值为:%d" , my);
    }
}

既然可以完全访问,为什么不一开始就干脆去掉不能访问这条规则?难道仅仅是为了在运行时免去查找的过程么?搞不懂架构OC语言的人。

当然,如果块就这点用法的话,那它就没有什么必要存在了,在实际中,用的最多的是回调。

二、页面传值

要完成这样的一个功能:

在ViewController A中,点击按钮,push到ViewController B中,在B中的输入框输入值,返回到A中,在A中的Label上显示出来

第一种方法:协议代理。 就像Android里的Fragment传值那样。

首先定义一个协议:

//ViewController A要服从该协议,实现协议中的方法
@protocol TransportDelegate <NSObject>
- (void)setTextValue:(NSString *)text;
@end

ViewController A中代码:

//ViewControllerA.m 文件
@interface ViewController ()<TransportDelegate>
@property (strong, nonatomic) IBOutlet UILabel *label;

@end
//点击Button进入下一个ViewCOntroller B页面
- (IBAction)nextBtnClicked:(id)sender
{
    NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
  //相当于让下一个视力控制器持有自身的一个引用
    nextVC.delegate = self;
    [self.navigationController pushViewController:nextVC animated:YES];
}

//实现协议TransportDelegate中的方法
#pragma mark - TransportDelegate method
- (void)setTextValue:(NSString *)text
{
    //self.nextVCInfoLabel是显示NextViewController传递过来的值
    self.label.text = tfText;
}

看到这,应该就可以猜到,ViewController B里,持有一个协议的引用,返回时,回调协议引用对象的方法:

@interface NextViewController : UIViewController
@property (nonatomic, assign) id<TransportDelegate> delegate;
@property (strong, nonatomic) IBOutlet TextField* textField;
@end

//NextViewController.m 文件
//返回前一个ViewController页面
- (IBAction)backBtnClicked:(id)sender {
    if (self.delegate && [self.delegate respondsToSelector:@selector(setTextValue:)]) {
        [self.delegate setTextValue:self.textField.text];
    }
    [self.navigationController popViewControllerAnimated:YES];
}

这就完成了页面间传值。总结来说就是,让B持有一个A的引用,在B中回调A中的方法,引用的桥梁是协议。用起来很麻烦,传个值而已还要定义个什么协议! 用Block就简单很多。

第二种方法:用Block

ViewController A中代码:

- (IBAction)btnClicked:(id)sender
{
    NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
  //这里才给ViewController B的块变量赋值
    nextVC.transportBlock = ^(NSString *text){
        [self setLabelText:text];
    };
    [self.navigationController pushViewController:nextVC animated:YES];
}
#pragma mark - setLabeText method
- (void)setLabelText:(NSString *)text
{
    self.label.text = text;
}

还是一样,看到这里,应该就可以猜到了,ViewController B里,直接调用块变量就可以:

//NextViewController.h 文件
@interface NextViewController : UIViewController
@property (nonatomic, copy) void (^transportBlock)(NSString *text);
@property (strong, nonatomic) IBOutlet TextField* textField;
@end
//NextViewContorller.m 文件
- (IBAction)backBtnClicked:(id)sender {
    if (self.transportBlock) {
        self.transportBlock(self.textField.text);
    }
    [self.navigationController popViewControllerAnimated:YES];
}

简单了许多,不用实现协议,虽然看起来也像反向代理.

时间: 2024-12-21 21:37:58

iOS Block理解的相关文章

写给喜欢用Block的朋友(ios Block)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/38090205 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 本文不讲block如何声明及使用,只讲block在使用过程中暂时遇到及带来的隐性危险. 主要基于两点进行演示: 1.block 的循环引用(retain cycle) 2.去除block产生的告警时,需注意问题. 有一次,朋友问我当一个对象中的b

iOS block并发

iOS block并发 2012-06-13 09:31 1351人阅读 评论(0) 收藏 举报 iosuiviewnetwork任务threadimage 这篇文章转自 http://anxonli.iteye.com/blog/1097777,集中与iOS的多核编程和内存管理,大家完全可以使用苹果的多核编程框架来写出更加responsive的应用. 多核运算 在iOS中concurrency编程的框架就是GCD(Grand Central Dispatch), GCD的使用非常简单.它把任务

# iOS Block的本质(三)

iOS Block的本质(三) 上一篇文章iOS Block的本质(二)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block对对象变量的捕获,ARC 环境 block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获同基本数据类型变量相同吗? 查看一下代码思考:当在block中访问的为对象类型时,对象什么时候会销毁? // ARC环境下代码 typedef void (^Block)(void); int main(int argc, const char *

iOS block从零开始

iOS block从零开始 在iOS4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调. block的结构 先来一段简单的代码看看: void (^myBlock)(int a) = ^(int a){ NSLog(@"%zd",a); }; NSLog(@"旭宝爱吃鱼"); myBlock(999); 输出结果: 2016-05-03 11:27:18.571 block[5340:706252] 旭宝爱吃鱼

(译)IOS block编程指南 1 介绍

Introduction(介绍) Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block ca

ios Block学习

ios block 回调传值,回调事件, 直接上代码 在firstVC里面的tableView 点击方法 ,里面点击跳到另一个nextVC,然后返回后的firstVC后回调值 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ NextViewController *next=[[NextViewController alloc]init]; __block Nex

IOS block 教程&lt;转&gt;

http://pernghh.pixnet.net/blog/trackback/eac87d412e/33563409 本文来自台湾的某开发人员的博客,被墙,感觉讲的比较易懂,所以引过来.文字简体化了,原来是繁体,变数=变量,这个注意一下. 本章学习目标: 1. 了解何谓block. 2. 了解block的使用方法. Block 是iOS在4.0之后新增的程式语法,严格来说block的概念并不算是基础程式设计的范围,对初学者来说也不是很容易了解,但是在iOS SDK 4.0之后,block几乎

iOS Block界面反向传值

在上篇博客 <iOS Block简介> 中,侧重解析了 iOS Block的概念等,本文将侧重于它们在开发中的应用. Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性.用维基百科的话来说,Block是Apple Inc.为C.C++以及Objective-C添加的特性,使得这些语言可以用类lambda表达式的语法来创建闭包.关于闭包,一句话解释简洁明了:闭包就是能够读取其它函数内部变量的函数. 在iOS开发中,Block有很多方面的用途,

iOS block 用法

1.定义Block /* 回传void ,参数也是void 的block*/ void (^blockReturningVoidWithVoidArgument)( void ); /* 回传整数,两个参数分别是整数和字元型态的block*/ int   (^blockReturningIntWithIntAndCharArguments)( int , char ); /* 回传void ,含有10 个block 的阵列,每个block 都有一个型态为整数的参数*/ void (^arrayO