OC教程6-代码块block回调

OC6-代码块回调

本章教程主要对代码块回调模式进行讲解,已经分析其他回调的各种优缺点和适合的使用场景。

  • 代码块机制
  • Block变量类型
  • Block代码封装及调用
  • Block变量对普通变量作用域的影响
  • Block回调接口使用

1,代码块机制

苹果公司在iOS4 SDK中首次支持代码块机制,随后代码块机制被广泛应用于各种编码场景,最常见的为回调机制,也成为Block回调。

代码块也称Block。是封装代码的一种机制,也可以称为匿名函数。

使用这种机制可以将一段代码放入一个Block变量中进行存储,该变量可以作为参数进行传递,也可以通过该变量调用其存储的代码。

2,Block变量类型

在OC语法中,创建一个变量首先要明确其类型。Block作为一个可以储存代码的变量,其类型相对特殊。

确定block变量的类型有两个因素:

  • 储存代码的返回值类型
  • 储存代码的参数列表

只要这两个因素一样,我们就可以说是相同的block类型。

现在我们举一个简单的例子,创建一个储存没有返回值,没有输入参数的代码的block类型。

void (^ varBlock)(void);

上面的代码声明了一个block变量,变量名为varBlock,其储存代码类型为没有返回值,没有输入参数。

如果想要储存有返回值,有输入参数的代码,同样可以声明响应的block变量进行使用。

int (^ varBlock1)(int a,int b);

上面的代码声明了一个block变量,变量名为varBlock1,其储存代码类型为int型返回值,有两个int型参数。

Block变量类型较为复杂,如果直接用这种方式进行声明变量十分容易储存。通常我们用typedef关键字将Block类型重命名,然后用相对简单的类型名进行声明变量的工作。

typedef void (^ BlockType1)(void);

BlockType1 var1;//var1与varBlock1为同一类型

3,Block代码封装及调用

有了Block变量,下面我们就要给变量赋值。

typedef void (^ BlockType1)(void);

BlockType1 var1;

var1 = ^(){NSLog(@"test")};

通过上述语法格式将代码封装在大括号内,并用var1变量进行储存。封装代码的过程中要注意一下几点:

  • ^符号开始为Block封装过程。
  • ^后面的小括号中写这段代码需要的参数。该参数有调用者进行赋值。
  • 小括号后面的大括号中写要封装的代码,且代码可以使用小括号中的参数。

下面举一个求两个数的和的代码封装过程。

typedef int (^BlockType)(int a,int b);

BlockType varBlock;

varBlock = ^(int a,int b){return a+b;};

将代码存入varBlock变量中后,便可以使用该变量调用代码。

int a = 4;
int b = 6;
int sum = varBlock(a,b);
NSLog(@"sum = %d",sum);//输出结果为10

Block变量也可以给同类型的变量赋值

BlockType varBlockTemp;
varBlockTemp = varBlock;
int sum = varBlockTemp(1,2);
NSLog(@"sum = %d",sum);//输出结果为3

将一段代码当做一个变量进行传递,Block这样的特性极大的方便了我们之后的编码工作

3,Block变量对普通变量作用域的影响

通过Block对象将代码进行封装的同时,有一个非常关键的问题我们需要明确讨论,即Block变量对普通变量作用域的影响。

通过一个简单案例来因此这个问题。见如下代码:

main()
{
    {
        int a = 1;
        {
            a = 2;
        }
        //此处输出a的值为2
    }
    //此处已经超出变量a的作用域,讨论a的值无意义。
}

这段代码很简单,通过大扩展来表示变量的作用域范围。再看下面代码:

typedef void (^ BlockType)(void);

BlockType var;

void fun1()
{
    int a = 10;
    var = ^(){NSLog(@"a = %d",a)};
}

void fun2()
{
    var();
}

main()
{
    fun1();
    fun2();
}

在fun2函数中调用var变量时,运行的是fun1中存入var变量的代码,且代码中的使用的变量a也是fun1中的局部变量。

正常状态下,变量a的作用域在fun1函数体大括号内。在函数体大括号外面使用a是没有意义的。

但此处情况特殊,变量a被block变量var所使用,所以var变量将a进行了一个复制操作,也就是我们在var的代码里面使用的a其实是a的副本。

我们看下面的代码:

typedef void (^ BlockType)(void);

BlockType var;

void fun1()
{
    int a = 10;
    var = ^(){NSLog(@"a = %d",a)};
    a = 20;
}

void fun2()
{
    var();
}

main()
{
    fun1();
    fun2();
}

这段代码的输出和上一段代码一样,不会因为fun1函数中a的值发生变化而导致block里面的a的值发生变化。原因是Block变量在使用局部变量是,会对局部变量进行一个复制操作,block变量中储存的代码使用的时局部变量的副本。

但是在某些特殊场合,我们需要改变局部变量可以引起block变量中代码的变化。这时候我们需要使用block全景变量。

block全景变量通过:__block来声明。

typedef void (^ BlockType)(void);

BlockType var;

void fun1()
{
    __block int a = 10;
    var = ^(){NSLog(@"a = %d",a)};
    a = 20;
}

void fun2()
{
    var();
}

main()
{
    fun1();
    fun2();
}

上文代码中,fun1中的变量a被block全景变量标识符所修饰,即变量a成为一个block全景变量。

其作用是,此时block封装代码时使用a变量,不会进行复制操作,也就表示,局部变量a与block代码中的a为同一个变量。所以,当前代码的运行结果为 a = 20。

4,Block回调接口使用

回调的本质为控件反馈自身信息,在面向对象编程中,控件需要调用方法反馈自身信息,而方法必须从属某个对象。所以之前的回调接口必须设置两个参数,一个反馈对象,一个反馈方法。

  • 在目标动作中,反馈对象为target,反馈方法为action,一个SEL类型的变量。
  • 在委托回调中,反馈对象为delegate,反馈方法为组件协议中声明的方法。

在Block回调中,因Block机制可以直接将代码封装如一个变量中,而且这个变量可以当做参数进行传递。利用这个机制,组件可以保存这段代码,在触发事件的时候直接调用此段代码,不需要设置反馈对象和反馈方法。

这里仍然用之前的开关最为例子:

typedef enum : NSUInteger {
    SwitchStateOff,//default
    SwitchStateOn,
} SwitchState;

typedef void(^SBlockType)(SwitchState state);

@interface SwitchB : NSObject

@property(nonatomic,assign,readonly)SwitchState currentState;

@property(nonatomic,strong)SBlockType changeStateBlockHandle;

@end

声明中的changeStateBlockHandle属性就是保存回调代码。设置回调,只需要将此属性赋值就可。

@interface Room : NSObject
@property (strong, nonatomic) Light *lightA;
@property (strong, nonatomic) SwitchB *s;

@end

@implementation Room
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.lightA = [[Light alloc] init];
        self.s = [[SwitchB alloc] init];

        __weak __block Room * copy_self = self;//打破强引用循环,后续章节会展开讲解

        self.s.changeStateBlockHandle = ^(SwitchState state)
        {
            if (state == SwitchStateOff)
            {
                [self.lightA turnOff];
            }
            else
            {
                [self.lightA turnOn];
            }
        };
    }
    return self;
}
@end

当开关的状态发生改变时,开关需要将自身状态反馈给使用者。当使用Block回调接口的组件时,需要将回调代码直接封装,赋值给组件响应的Block类型的属性即可。当状态改变时,封装的代码便被组件调用。

时间: 2024-10-13 02:48:01

OC教程6-代码块block回调的相关文章

[转]iOS代码块Block

代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中,常用于GCD.动画.排序及各类回调 注: Block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码 Block变量的声明.赋值与调用 Block变量的声明 Block变量的声明格式为: 返回值类型(^Block名字)(参数列表); /

一篇文章看懂iOS代码块Block

iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中,常用于GCD.动画.排序及各类回调 注: Block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码 Block变量的声明.赋值与调用 Block变量的声明 Block变量的声明格式为: 返回值类型(^Bl

iOS学习之代码块(Block)

代码块(Block) (1)主要作用:将一段代码保存起来,在需要的地方调用即可. (2)全局变量在代码块中的使用: 全局变量可以在代码块中使用,同时也可以被改变,代码片段如下: 1 int local = 1;//注意:全局变量 2 void (^block0)(void) = ^(void){ 3 local ++; 4 NSLog(@"local = %d",local); 5 }; 6 block0(); 7 NSLog(@"外部 local = %d",lo

java学习教程之代码块

学编程吧java学习教程之代码块发布了,欢迎通过xuebiancheng8.com来访问 java中的代码块包括下面几种: 1.普通代码块 2.构造代码块 3.静态代码块 1.普通代码块很简单看下面这个例子: public class Test{ public static void main(String args[]){ { //此处就是普通代码块,普通代码块中的代码按顺序执行 System.out.println("hello"); } } } 2.构造代码块 public cl

Objective-C - 代码块block

代码块block /* block要掌握的东西 1> 如何定义block变量 int (^sumBlock)(int, int); void (^myBlock)(); 2> 如何利用block封装代码 ^(int a, int b) { return a - b; }; ^() { NSLog(@"----------"); }; ^ { NSLog(@"----------"); }; 3> block访问外面变量 * block内部可以访问外

Objective-C 代码块(block)的使用

代码块本质上是和其他变量类似.不同的是,代码块存储的数据是一个函数体.使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值. 脱字符(^)是块的语法标记.按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码).下图是如何把块变量赋值给一个变量的语法讲解: 按照调用函数的方式调用块对象变量就可以了:int result = myBlock(4); // result是 28 1.参数是NSString*的代码块 [cpp] view plaincopy voi

OC教程5-委托delegate模式回调

OC5-委托模式回调 本章主要讲解委托模式已经通过委托模式实现的回调接口. 1,委托模式 委托模式是OC语法独有的开发模式.是基于组件拼装的一种快速开发模式.该模式下,可以保证组件的高度灵活性和通用性.属于组件的一种开放式接口. 下面通过一个现实生活中的场景简单理解下委托模式的应用. 例如我们现在有一个公司.公司想要进行IPO.可是公司老总并不熟悉资本操作,这时候就需要委托一个人或者一个机构来作这件事. 公司首先要提出能做IPO这件事的详细要求,然后在通过猎头寻找合适的人选. 用代码描述应该是这

Objective-C语法之代码块(block)的使用

代码块本质上是和其它变量相似.不同的是,代码块存储的数据是一个函数体.使用代码块是,你能够像调用其它标准函数一样,传入參数数,并得到返回值. 脱字符(^)是块的语法标记.依照我们熟悉的參数语法规约所定义的返回值以及块的主体(也就是能够执行的代码).下图是怎样把块变量赋值给一个变量的语法解说: 依照调用函数的方式调用块对象变量就能够了:int result = myBlock(4); // result是 28 1.參数是NSString*的代码块 void (^printBlock)(NSStr

Objective-C语法之代码块(block)的使用(转)

代码块本质上是和其他变量类似.不同的是,代码块存储的数据是一个函数体.使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值. 脱字符(^)是块的语法标记.按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码).下图是如何把块变量赋值给一个变量的语法讲解: 按照调用函数的方式调用块对象变量就可以了:int result = myBlock(4); // result是 28 1.参数是NSString*的代码块 void (^printBlock)(NSStr