Block(十四)

 

block块是一种语法,里边封装了用户自定义的代码块,用来实现某些方法功能。

block的定义方式:

与函数指针的定义很像,只是把函数指针的*号改成 ^ 号。

先写^,然后写返回值类型,接着是参数类型,参数名,然后是大括号,分号,大括号里的代码。

        /*

        //定义Block

        //返回值可以自己推断出来是什么类型的。

        ^int(int num1,int num2){

            return num1 + num2;

        };

解释:

^ :block的标志;

第一个int:返回值类型;

int num1:第一个参数类型和参数名;

int num2:第二个参数类型和参数名;

{ } 里是我们想实现的某些功能,不能少了分号。

一些练习:

        //练习

        //无参无返回值,打印hello world

        ^void(){

            NSLog(@"hello World");

        }();//在此加上小括号()就是Block调用

       

        ^(){

            NSLog(@"hello world");

        };

        //无参有返回值,返回一个字符串NSString

        ^NSString *(){

            return @"hello world";

        };

       

        ^(){//会自动根据return返回的东西进行判断返回值是什么类型的。

            return @"hello world";

        };

block的调用,可以在定义的时候,在大括号{}加一个(),()里边是传递的参数。

block的定义,返回值类型可以省略,因为可以根据block里的返回值,自动判断返回值的类型。但是参数类型和参数名不能省略。

block变量来保存block块

与指针函数一样,我们把指针函数的方式定义block变量,但是要把* 号改成 ^号。方式如下:返回值 + (^变量名)+(参数类型和个数) = block块

        //定义一个BLock变量,保存Block块

        // = 号前面是一个变量(类似指针函数,只是把括号里的*号改成^号即可)

        //类型不要加括号

        void (^b)() = ^void(){

            NSLog(@"Hello,world");

        };

       

        int (^b11)(int,int) = ^int(int num1 ,int num2){

            return num1 +num2;

        };

       

        NSString *(^b3)() = ^NSString *(){

            return @"hello world";

        };

block的调用

block的调用,就是block定义变量后,用变量名+括号(),括号里放参数,与C语言的方法调用很相似。

        //Block调用,使用Block变量加上括号(),里边放参数。

        int i = b11(1, 1);

        NSLog(@"%d",i);

        b();

        NSLog(@"%@",b3());

 

 

 

 

练习:定义一个block,实现把字符串转换成整型数。

 

        //练习

        int (^b22)(NSString *) = ^int (NSString *s){

            int num = [s intValue];

            return num;

        };

        NSLog(@"%d", b22(@"999999994"));//调用block

练习:定义一个block,实现数组排序

        //练习

        //Block,返回值Nsarray,参数NSArray(都是NSString),功能,按升序排。

        NSArray *(^sort)(NSArray *) = ^NSArray *(NSArray *arr){

           

            NSArray *temp = [arr sortedArrayUsingSelector:@selector(compare:)];

           

            return temp;

        };

        NSArray *temp1 = [[NSArray alloc]initWithObjects:@"f",@"b",@"c",@"d",@"e", nil];

        NSArray *arr = sort(temp1);

        NSLog(@"%@",arr);

练习:定义block实现比较两个数的大小:

        //block 返回值 int,参数两个int

        //功能,返回两个数最大值

        int (^max)(int ,int ) = ^int (int num1, int num2){

            return num1 > num2? num1:num2;

        };

        int num = max(311,5);

        NSLog(@"%d",num);

练习:返回3个数乘积

 

        //block 返回值:float类型,参数3个float

        //功能:求三个数的乘积

       

        float (^mul)(float ,float,float) = ^float (float num1,float num2,float num3){

            return num1 * num2 *num3;

        };

     

        float n = mul(7,8,9);

        NSLog(@"%.2f",n);

 

typedef给block类型取一个新名

与指针函数一样,用typedef给block取一个名字,方式与函数指针一样,只要把 * 号改成 ^号即可。就可以直接使用新名字定义一个变量。

#import <Foundation/Foundation.h>

//typedef

//typedef int(^NewBlock)(int ,int );^写在这里也行

//typedef int(NewBlock)(int ,int );//^不写在这里也行,那就得写在定义的时候

int main(int argc, const char * argv[]) {

@autoreleasepool {

        //typedef

        NewBlock nb = ^int (int num1 ,int num2 ){

        NewBlock ^nb = ^int (int num1 ,int num2 ){//^号写在nb这里

            return num1 + num2;

        };

        int i = nb(12,23);

        NSLog(@"%d",i);//2015-04-20 16:32:36.069 OCLesson6_Block[2260:131999] 35

    }

    return 0;

}

练习:

#import <Foundation/Foundation.h>

typedef int (StringToInt) (NSString *);

int main(int argc, const char * argv[]) {

@autoreleasepool {

        StringToInt ^sti = ^int (NSString *str){

            return [str intValue];

        };

        int num = sti(@"2222333");

        NSLog(@"%d",num);

    }

    return 0;

}

局部变量

局部变量在block里可以读取,但是不能改值。所以,如果想改变一个变量的值,有三种方法:

1、把局部变量放到方法外面,使之成为全局变量

2、在方法里,定义的局部变量,用双下划线block来声明:__block(下划线有两条)。

3、在方法里定义的局部变量,用static修饰。

如果局部变量是指针的话,在block里,可以改值,但是改得值是这个指针指向的堆中的地址里的值,不是改变这个指针本身的值,所以是这个指针根本就没有变化,变化的是指针所指向的地址里的值。

 

int i = 10;//局部变量

//        static int i = 10;//静态修饰局部变量

        __block int i = 10;//声明是__block,即把变量放到静态区了。

        VoidBlock ^vb = ^void (){

            //局部变量的值block块中,可以访问。但是不能改值。

            //如果想改变变量有3种方式:

            //1、变量变为全局变量(把变量定义放到函数外面)

            //2、使用下划线下划线block( __block )声明的变量(两个下划线)

            //3、static修饰局部变量

            i = 110;

            NSLog(@"%d",i);//2015-04-20 16:49:48.813 OCLesson6_Block[2397:137508] 10

        };

        NSLog(@"%d",i);//2015-04-20 16:50:14.376 OCLesson6_Block[2406:137717] 110

        vb();

        NSLog(@"%d",i);//2015-04-20 16:50:39.051 OCLesson6_Block[2415:137950] 110

        */

        /*

        NSMutableArray *array = [[NSMutableArray alloc]init];

       

        VoidBlock (^vb2) = ^void (){

            //这个时候,array是指针,保存地址,地址没有改变,改变的是array所指向的堆区的值。所以没有错误。

            [array addObject:@"2"];

            //打印添加元素时的地址

            NSLog(@"%p",array);//2015-04-20 17:05:02.246 OCLesson6_Block[2480:142637] 0x10030cb90

        };

       

        vb2();

        NSLog(@"%@",array);

//        2015-04-20 17:00:25.266 OCLesson6_Block[2452:141334] (

//        2

//        )

        //打印添加元素后的地址

        NSLog(@"%p",array);//2015-04-20 17:05:02.246 OCLesson6_Block[2480:142637] 0x10030cb90

block作为函数参数

这个设计很妙,就是很多时候,我们是得不到.m这个实现方法的文件的,我们只有.h文件里声明的接口。此时我们想改变或者添加一些功能,不能在.m文件里改,只能在我们使用的方法里增加一些代码。此时,就可以在block里添加我们想要实现的功能,然后把这个block当做参数传入.m中。事先,我们在.m中如果设置了调用block的方法,那么我们把block传入这个方法,就可以执行我们传入的block里边的代码块,实现功能。其实与函数指针作为函数参数一样,把指针传入某个方法里,然后这个方法执行的时候,是去传入的指针所指向的函数执行那个函数。

Person.h

#import <Foundation/Foundation.h>

typedef void (^MyBlock)();

@interface Person : NSObject{

    NSString *_name;

    NSInteger _age;

}

 

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;

 

- (NSString *)name;

- (NSInteger)age;

 

- (void )setName:(NSString *)name;

- (void )setAge:(NSInteger)age;

 

//将 block作为参数传入()其实就是一段代码传入

- (void)sayWhat:(MyBlock )mb;

@end

Person.m

#import "Person.h"

@implementation Person

//将 block作为参数传入()其实就是一段代码传入

- (void)sayWhat:(MyBlock )mb{

    //假设有一段执行代码

    //调用block()其实就是在执行传进来的那一段代码。

    mb();

    //执行代码

}

 

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age{

    self = [super init];

    if (self) {

        _name  = name;

        _age = age;

    }

    return self;

}

 

//getter

- (NSString *)name{

    return _name ;

}

- (NSInteger)age{

    return _age;

}

//setter

- (void )setName:(NSString *)name{

    _name = name;

}

- (void )setAge:(NSInteger)age{

    _age = age ;

}

- (NSString *)description

{

    return [NSString stringWithFormat:@"name = %@,age = %ld", _name,_age];

}

 

 

@end

 

main.m

#import <Foundation/Foundation.h>

#import "Person.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

//        Person *p = [[Person alloc]init];

//        //这个时候,这个block(这段代码作为参数传入方法中)。

//        [p sayWhat:^void(){

//           

//            NSLog(@"hello bobo");

//           

//        }];

    }

    return 0;

}

执行过程,在main.m和Person.m打断点即可知道

练习:Person.h和Person.m跟上面的一样。

main.m

        //练习

        Person *p1 = [[Person alloc]initWithName:@"AAA" age:18];

        Person *p2 = [[Person alloc]initWithName:@"CCC" age:12];

        Person *p3 = [[Person alloc]initWithName:@"BBB" age:19];

       

        NSArray *sortArr = [NSArray arrayWithObjects:p1,p2,p3, nil];

        //1.按照年龄升序

        NSArray *sorted = [sortArr sortedArrayUsingComparator:^NSComparisonResult(Person *obj1,Person *obj2){

            if (obj1.age > obj2.age) {

                return NSOrderedDescending;

            }else if(obj1.age == obj2.age){

                return NSOrderedSame;

            }else{

                return NSOrderedAscending;

            }

        }];

        NSLog(@"%@",sorted);

posted @ 2016-01-10 16:01  恒远也  阅读(207)  评论(0编辑  收藏  举报