关于block的一点思考--底层可否用全局保存上层传下来的block

本文通过具体示例探讨了Block作为全局变量和类成员变量时的行为差异,尤其是在嵌套调用场景下的表现。实验证明,即使Block被替换,也能正常执行剩余代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


关于block的一点思考


上层传下来的block,用全局保存,那么上层可以嵌套这个block吗?

block在执行中又对全局block重新赋值,会出现什么问题吗,为什么?



以下demo,BlockTest模拟底层提供api,

 fun1: Block: 模拟api接收block入参并保存block副本,

底层处理完事情后,执行保存在全局的block


测试方法中,block执行过程中又调用了BlockTest的fun1: block:方法

这时底层全局block还没执行完,又被自身在执行过程中赋值上新的block

赋值之后还没执行完的block是否能正常继续执行呢?


.h文件

#import <Foundation/Foundation.h>



typedef int(^TestBlock)(int p1);



@interface BlockTest : NSObject


-(int)fun1:(int)p1 Block:(TestBlock)block;


@end



.m文件

#import "BlockTest.h"



static TestBlock testBlock;

static int gp1;


@implementation BlockTest


-(int)fun1:(int)p1 Block:(TestBlock)block

{

    NSLog(@"begin fun1 P1=%d thread=%@",p1,[NSThread currentThread]);

    gp1 = p1;

    testBlock = [block copy];

//底层尝试用3种方式来执行block

//    [self performSelectorInBackground:@selector(ExcuteBlock) withObject:nil];

    [self performSelector:@selector(ExcuteBlock) withObject:nil afterDelay:0.1];

//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),/* dispatch_get_main_queue(),*/ ^{

//        [self ExcuteBlock];

//    });

    

    NSLog(@"end fun1 P1=%d ",p1);

    return 0;

}


-(void)ExcuteBlock

{

    NSLog(@"befor testBlock p1=%d thread=%@",gp1,[NSThread currentThread]);

    testBlock(gp1);//如果有嵌套,那么这句在执行过程中会把自身给替换掉,这时替换语句后面的代码,以及下面的代码是否能正常继续运行

    NSLog(@"after testBlock p1=%d thread=%@",gp1,[NSThread currentThread]);

    

}


-(void)dealloc{

    NSLog(@"dealloc %@",self);

}


@end



测试方法


-(void)testNestedGlobalBlock

{

    BlockTest * blockTest = [[BlockTest alloc] init];

    [blockTest fun1:1 Block:^int(int p1) {

        NSLog(@"begin block 1");

        NSLog(@"即将替换掉当前执行的block");

        [blockTest fun1:2 Block:^int(int p1) {

            NSLog(@"begin block 2");

            

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                NSLog(@"dispatch_after");

            });

            

            NSLog(@"end block 2");

            return 2;

        }];

        NSLog(@"被替换后,block继续运行");

        NSLog(@"end block 1");

        return 1;

    }];

    

    NSLog(@"testNestedGlobalBlock over");

}


测试结果

底层模拟了3种方式来执行方法,从而执行block,下面是执行过程中的输出结果

从这3种输出结果来看,正在执行中得block,虽然其对应的全局变量被替换掉了,但却还能正常往下执行


 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),/* dispatch_get_main_queue(),*/ ^{

        [self ExcuteBlock];

    });

2015-01-07 15:15:38.820 test[1278:36599] begin fun1 P1=1 thread=<NSThread: 0x7ffa0b42ee20>{number = 1, name = main}

2015-01-07 15:15:38.821 test[1278:36599] end fun1 P1=1 

2015-01-07 15:15:38.821 test[1278:36599] testNestedGlobalBlock over

2015-01-07 15:15:39.852 test[1278:36676] befor testBlock p1=1 thread=<NSThread: 0x7ffa0b768190>{number = 2, name = (null)}

2015-01-07 15:15:39.852 test[1278:36676] begin block 1

2015-01-07 15:15:39.853 test[1278:36676] 即将替换掉当前执行的block

2015-01-07 15:15:39.853 test[1278:36676] begin fun1 P1=2 thread=<NSThread: 0x7ffa0b768190>{number = 2, name = (null)}

2015-01-07 15:15:39.854 test[1278:36676] end fun1 P1=2 

2015-01-07 15:15:39.854 test[1278:36676] 被替换后,block继续运行

2015-01-07 15:15:39.855 test[1278:36676] end block 1

2015-01-07 15:15:39.855 test[1278:36676] after testBlock p1=2 thread=<NSThread: 0x7ffa0b768190>{number = 2, name = (null)}

2015-01-07 15:15:40.866 test[1278:36676] befor testBlock p1=2 thread=<NSThread: 0x7ffa0b768190>{number = 2, name = (null)}

2015-01-07 15:15:40.866 test[1278:36676] begin block 2

2015-01-07 15:15:40.867 test[1278:36676] end block 2

2015-01-07 15:15:40.868 test[1278:36676] after testBlock p1=2 thread=<NSThread: 0x7ffa0b768190>{number = 2, name = (null)}

2015-01-07 15:15:40.868 test[1278:36676] dealloc <BlockTest: 0x7ffa0b527180>

2015-01-07 15:15:40.977 test[1278:36599] dispatch_after




    [self performSelectorInBackground:@selector(ExcuteBlock) withObject:nil];

2015-01-07 15:15:14.735 test[1263:36135] begin fun1 P1=1 thread=<NSThread: 0x7ffb10d21c80>{number = 1, name = main}

2015-01-07 15:15:14.737 test[1263:36135] end fun1 P1=1 

2015-01-07 15:15:14.737 test[1263:36135] testNestedGlobalBlock over

2015-01-07 15:15:14.738 test[1263:36218] befor testBlock p1=1 thread=<NSThread: 0x7ffb10c16940>{number = 2, name = (null)}

2015-01-07 15:15:14.738 test[1263:36218] begin block 1

2015-01-07 15:15:14.738 test[1263:36218] 即将替换掉当前执行的block

2015-01-07 15:15:14.739 test[1263:36218] begin fun1 P1=2 thread=<NSThread: 0x7ffb10c16940>{number = 2, name = (null)}

2015-01-07 15:15:14.739 test[1263:36219] befor testBlock p1=2 thread=<NSThread: 0x7ffb10e8a170>{number = 3, name = (null)}

2015-01-07 15:15:14.740 test[1263:36219] begin block 2

2015-01-07 15:15:14.740 test[1263:36219] end block 2

2015-01-07 15:15:14.740 test[1263:36219] after testBlock p1=2 thread=<NSThread: 0x7ffb10e8a170>{number = 3, name = (null)}

2015-01-07 15:15:14.741 test[1263:36218] end fun1 P1=2 

2015-01-07 15:15:14.741 test[1263:36218] 被替换后,block继续运行

2015-01-07 15:15:14.742 test[1263:36218] end block 1

2015-01-07 15:15:14.838 test[1263:36218] after testBlock p1=2 thread=<NSThread: 0x7ffb10c16940>{number = 2, name = (null)}

2015-01-07 15:15:14.838 test[1263:36218] dealloc <BlockTest: 0x7ffb10c16c10>

2015-01-07 15:15:14.841 test[1263:36135] dispatch_after



    [self performSelector:@selector(ExcuteBlock) withObject:nil afterDelay:0.1];

2015-01-07 15:14:12.868 test[1243:35475] begin fun1 P1=1 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:12.869 test[1243:35475] end fun1 P1=1 

2015-01-07 15:14:12.870 test[1243:35475] testNestedGlobalBlock over

2015-01-07 15:14:12.971 test[1243:35475] befor testBlock p1=1 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:12.972 test[1243:35475] begin block 1

2015-01-07 15:14:12.972 test[1243:35475] 即将替换掉当前执行的block

2015-01-07 15:14:12.972 test[1243:35475] begin fun1 P1=2 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:12.972 test[1243:35475] end fun1 P1=2 

2015-01-07 15:14:12.972 test[1243:35475] 被替换后,block继续运行

2015-01-07 15:14:12.972 test[1243:35475] end block 1

2015-01-07 15:14:12.972 test[1243:35475] after testBlock p1=2 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:13.075 test[1243:35475] befor testBlock p1=2 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:13.075 test[1243:35475] begin block 2

2015-01-07 15:14:13.075 test[1243:35475] end block 2

2015-01-07 15:14:13.076 test[1243:35475] after testBlock p1=2 thread=<NSThread: 0x7ff481c287f0>{number = 1, name = main}

2015-01-07 15:14:13.076 test[1243:35475] dealloc <BlockTest: 0x7ff481d49540>

2015-01-07 15:14:13.180 test[1243:35475] dispatch_after





不过与其在那边担心用全局block会不会有问题,还不如做成局部的,那就不会有问题了吧,

下面这个demo,把block做成类的一个属性



.h文件

#import <Foundation/Foundation.h>


typedef int(^TestBlock)(int p1);



@interface BlockTest2 : NSObject


@property(nonatomic,copy)TestBlock testBlock;


-(int)fun1:(int)p1 Block:(TestBlock)block;


@end


.m文件

#import "BlockTest2.h"


static int gp1;


@implementation BlockTest2


-(int)fun1:(int)p1 Block:(TestBlock)block

{

    NSLog(@"begin fun1 P1=%d thread=%@",p1,[NSThread currentThread]);

    gp1 = p1;

    self.testBlock = block;

//底层尝试用3种方式来执行block

//    [self performSelectorInBackground:@selector(ExcuteBlock) withObject:nil];

//        [self performSelector:@selector(ExcuteBlock) withObject:nil afterDelay:0.1];

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)),dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),/* dispatch_get_main_queue(),*/ ^{

            [self ExcuteBlock];

        });

    

    NSLog(@"end fun1 P1=%d ",p1);

    return 0;

}


-(void)ExcuteBlock

{

    NSLog(@"befor testBlock p1=%d thread=%@",gp1,[NSThread currentThread]);

    self.testBlock(gp1);

    NSLog(@"after testBlock p1=%d thread=%@",gp1,[NSThread currentThread]);

    

}


-(void)dealloc{

    NSLog(@"dealloc %@",self);

}


@end


测试方法


-(void)testNestedMemberBlock

{

    BlockTest2 * blockTest = [[BlockTest2 alloc] init];

    [blockTest fun1:1 Block:^int(int p1) {

        NSLog(@"begin block 1");

        BlockTest2 * blockTest1  = [[BlockTest2 alloc] init];

        [blockTest1 fun1:2 Block:^int(int p1) {

            NSLog(@"begin block 2");

            

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                NSLog(@"dispatch_after");

            });

            

            NSLog(@"end block 2");

            return 2;

        }];

        

        NSLog(@"end block 1");

        return 1;

    }];

    

    NSLog(@"testNestedMemberBlock over");

}


测试结果


        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)),dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),/* dispatch_get_main_queue(),*/ ^{

            [self ExcuteBlock];

        });

2015-01-07 15:10:50.435 test[1178:33136] begin fun1 P1=1 thread=<NSThread: 0x7feb21e25810>{number = 1, name = main}

2015-01-07 15:10:50.436 test[1178:33136] end fun1 P1=1 

2015-01-07 15:10:50.436 test[1178:33136] testNestedMemberBlock over

2015-01-07 15:10:51.516 test[1178:33228] befor testBlock p1=1 thread=<NSThread: 0x7feb21d65e40>{number = 2, name = (null)}

2015-01-07 15:10:51.516 test[1178:33228] begin block 1

2015-01-07 15:10:51.517 test[1178:33228] begin fun1 P1=2 thread=<NSThread: 0x7feb21d65e40>{number = 2, name = (null)}

2015-01-07 15:10:51.518 test[1178:33228] end fun1 P1=2 

2015-01-07 15:10:51.518 test[1178:33228] end block 1

2015-01-07 15:10:51.518 test[1178:33228] after testBlock p1=2 thread=<NSThread: 0x7feb21d65e40>{number = 2, name = (null)}

2015-01-07 15:10:51.519 test[1178:33228] dealloc <BlockTest2: 0x7feb21d6cae0>

2015-01-07 15:10:52.577 test[1178:33228] befor testBlock p1=2 thread=<NSThread: 0x7feb21d65e40>{number = 2, name = (null)}

2015-01-07 15:10:52.577 test[1178:33228] begin block 2

2015-01-07 15:10:52.578 test[1178:33228] end block 2

2015-01-07 15:10:52.578 test[1178:33228] after testBlock p1=2 thread=<NSThread: 0x7feb21d65e40>{number = 2, name = (null)}

2015-01-07 15:10:52.579 test[1178:33228] dealloc <BlockTest2: 0x7feb21c2a000>

2015-01-07 15:10:52.688 test[1178:33136] dispatch_after




    [self performSelectorInBackground:@selector(ExcuteBlock) withObject:nil];

2015-01-07 15:12:03.972 test[1201:34017] begin fun1 P1=1 thread=<NSThread: 0x7fb19870b040>{number = 1, name = main}

2015-01-07 15:12:03.973 test[1201:34017] end fun1 P1=1 

2015-01-07 15:12:03.974 test[1201:34017] testNestedMemberBlock over

2015-01-07 15:12:03.974 test[1201:34093] befor testBlock p1=1 thread=<NSThread: 0x7fb198638ed0>{number = 2, name = (null)}

2015-01-07 15:12:03.974 test[1201:34093] begin block 1

2015-01-07 15:12:03.975 test[1201:34093] begin fun1 P1=2 thread=<NSThread: 0x7fb198638ed0>{number = 2, name = (null)}

2015-01-07 15:12:03.978 test[1201:34094] befor testBlock p1=2 thread=<NSThread: 0x7fb198418880>{number = 3, name = (null)}

2015-01-07 15:12:03.979 test[1201:34094] begin block 2

2015-01-07 15:12:03.979 test[1201:34094] end block 2

2015-01-07 15:12:03.979 test[1201:34094] after testBlock p1=2 thread=<NSThread: 0x7fb198418880>{number = 3, name = (null)}

2015-01-07 15:12:03.980 test[1201:34093] end fun1 P1=2 

2015-01-07 15:12:03.980 test[1201:34093] end block 1

2015-01-07 15:12:03.981 test[1201:34093] dealloc <BlockTest2: 0x7fb198416ef0>

2015-01-07 15:12:03.981 test[1201:34093] after testBlock p1=2 thread=<NSThread: 0x7fb198638ed0>{number = 2, name = (null)}

2015-01-07 15:12:04.030 test[1201:34093] dealloc <BlockTest2: 0x7fb198641a50>

2015-01-07 15:12:04.084 test[1201:34017] dispatch_after



        [self performSelector:@selector(ExcuteBlock) withObject:nil afterDelay:0.1];

2015-01-07 15:13:07.607 test[1225:34701] begin fun1 P1=1 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.608 test[1225:34701] end fun1 P1=1 

2015-01-07 15:13:07.609 test[1225:34701] testNestedMemberBlock over

2015-01-07 15:13:07.708 test[1225:34701] befor testBlock p1=1 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.709 test[1225:34701] begin block 1

2015-01-07 15:13:07.709 test[1225:34701] begin fun1 P1=2 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.709 test[1225:34701] end fun1 P1=2 

2015-01-07 15:13:07.709 test[1225:34701] end block 1

2015-01-07 15:13:07.709 test[1225:34701] after testBlock p1=2 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.709 test[1225:34701] dealloc <BlockTest2: 0x7f975952b180>

2015-01-07 15:13:07.811 test[1225:34701] befor testBlock p1=2 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.811 test[1225:34701] begin block 2

2015-01-07 15:13:07.812 test[1225:34701] end block 2

2015-01-07 15:13:07.812 test[1225:34701] after testBlock p1=2 thread=<NSThread: 0x7f975971d4b0>{number = 1, name = main}

2015-01-07 15:13:07.813 test[1225:34701] dealloc <BlockTest2: 0x7f9759606310>

2015-01-07 15:13:07.917 test[1225:34701] dispatch_after




看起来执行也是没问题,且不用当心block被替换掉得问题,因为每次都是给一个新的对象赋值block属性



本来还当心BlockTest作为局部变量,会不会在block实际执行前就销毁了,不过看看日志,发现不会的,原因吗,我也不懂,真的发现自己是那么的无知

还有一点是,block在赋值时,用不用copy,区别在哪?





想多了解block,以下几篇文章可参考下


iOS BlockARC/ARC下的实用总结

http://www.tekuba.net/program/349/


【小测试】你真的知道blocksObjective-C中是怎么工作的吗?(获奖公布)

http://www.cocoachina.com/bbs/read.php?tid=152222


iOSBlock介绍(一)基础

http://mobile.51cto.com/hot-403897.htm


iOSBlock介绍(二)内存管理与其他特性

http://mobile.51cto.com/hot-403914.htm


iOSblock介绍(三)揭开神秘面纱()

http://mobile.51cto.com/hot-403931.htm


iOSblock介绍(四)揭开神秘面纱()

http://mobile.51cto.com/hot-403935.htm



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值