iOS开发--当Block、代理、通知遇到女朋友

2 篇文章 0 订阅
  • 什么是Block?
  • 为什么使用Block?
  • 怎么使用Block?

本文将从这三个问题入手来逐渐了解Block。
本文使用的范例传送门:https://github.com/Elbertz/ZDXBlockStudy


什么是Block?

首先我们先来观察一下block的书写格式

a (^b)(c,d)=^(c name1,d name2){};
a:Block的返回值类型,可以为空(void);
b:Block对象名称,可以理解为变量名;
^:块的语法标记,声明b为一个Block对象;
c:第一个参数类型
d:第二个参数类型
name1,name2:参数名;
{}:Block代码块的主题部分。

有人认为Block是代码块,以闭包形式存在的一段代码良好的独立性和可交互性;
也有人把Block当作OC的匿名函数,可以很好的传递参数;
还有人认为Block是一种特殊的数据类型,创建的Block对象可以更好的被上下文所调用;
还有一群人,他们觉得Block就是Block,盲目而片面的定义掩盖了它简易精妙的使用,因此他们从使用场景中描述Block是什么。

为什么使用Block?

Block作为参数、返回值可以更便捷的在各个场景间传递;
Block作为回调可以广泛的使用在多线程GCD、动画、排序的情形下;

下面是Block的基础使用,对Block的使用思路清晰的童鞋可以通过下面的2个案例进行深度学习:
Block实现各种排序:https://github.com/JiongXing/JXSort
AFNetworking:https://github.com/AFNetworking/AFNetworking

怎么使用Block?

在使用之前,我们先对Block在ARC和MRC环境下使用的基础知识点普及:
ARC:系统会帮你管理你自己创建的对象的内存
MRC:你需要管理你自己创建的对象的内存
当你创建一个新的project时默认是ARC环境,你可以在Build Setting下关闭自动引用记数切换到MRC环境。

为什么使用copy来修饰Block?

使用copy可以将Block从栈上转移到堆上
MRC下,默认是栈上为了控制Block生命周期,需要将其copy的堆上,不可以用reatin代替。 ARC下大多数情况默认是在堆上,但是因为一般遵循传统,会写上copy,但是可以用strong来代替。

ARC下需不需要对Block进行手动copy?

不用手动copy的情形?

1.当 Block 被强引用时。
2.系统的 API 中带有 usingBlock 时。
3.Block 作为函数返回值。

用手动copy的情形?

当block 作为函数参数的时候,在 arc 下我们自定义的Block 要写上 copy。

注意:copy的特点
1.如果原来在栈上,通过copy,被复制到堆上。
2.如果原来在全局数据区,不会发生改变
3.如果在堆区:其引用计数加1

在Block使用过程中,如何避免循环引用?

ARC情况下

1.如果用copy修饰Block,该Block就会存储在堆空间。则会对Block的内部对象进行强引用,导致循环引用。内存无法释放。
2.如果用weak修饰Block,该Block就会存放在栈空间。不会出现循环引用问题。

MRC情况下

用copy修饰后,如果要在Block内部使用对象,则需要进行(__block typeof(Target) blockTarget = Target )处理。在Block里面用blockTarget进行操作。

__block在MRC下有两个作用
1. 允许在Block中访问和修改局部变量
2. 禁止Block对所引用的对象进行隐式retain操作
__block在ARC下只有一个作用
1. 允许在Block中访问和修改局部变量
__weak可以避免在ARC下Block造成循环引用

使用场景?

标准范式:

// 1.使用typedef定义Block类型
typedef int(^MyBlock)(int, int);

// 2.定义一个形参为Block的OC函数
- (void)useBlockForOC:(MyBlock)aBlock
{
    NSLog(@"result = %d", aBlock(300,200));
}

// 3.声明并赋值定义一个Block变量
MyBlock addBlock = ^(int x, int y){
    return x+y;
};

// 4.以Block作为函数参数,把Block像对象一样传递
[self useBlockForOC:addBlock];

// 将第3点和第4点合并一起,以内联定义的Block作为函数参数
[self useBlockForOC:^(int x, int y){
    return x+y;
}];
情景一:传递参数

viewController 控制器1,testViewController 控制器2,控制器1跳转到控制器2,然后在控制器2触发事件回调修改控制器1的对应控件的背景色为红色?

testViewController

typedef void (^myBlock)(UIColor* color);
@property (nonatomic,copy)myBlock block1;

UIColor *color = [UIColor redColor];
//给Block传入参数color
self.block1(color);
[self.navigationController popViewControllerAnimated:YES];

viewController

//plan1
    testViewController *testVC = [[testViewController alloc]init];
    testVC.block1 = ^(UIColor *color){
        label1.backgroundColor = color;
    };
    [self.navigationController pushViewController:testVC animated:YES];

//plan2
    //当block中使用了self时,需要对self添加__weak关键字,避免循环调用

    __weak typeof(self) weakself = self;//等价于下一行代码
    //__weak UIViewController* weakself = self;
    testViewController *testVC = [[testViewController alloc]init];
    testVC.block1 = ^(UIColor *color){
        weakself.label2.backgroundColor = color;
    };
    [self.navigationController pushViewController:testVC animated:YES];

当在Block代码块中使用了self,请注意要避免循环应用。

Q:说好的女朋友呢? 看好了,女朋友的问题来了
一天,你的女朋友逛淘宝的时候对你说,这个包包好漂亮,买给我嘛?么么哒! 面对糖衣炮弹轰击对你默默的登录了自己的支付宝账号点下了确认支付的按钮。
女朋友想买的东西委托给你去买,这是代理模式的典型案例,同样也可用block实现。
1)代理模式实现

    girlFriends *gf = [girlFriends shareInstance];
    gf.delegate = self;

    [gf buyALadiesBackpackForMe];

2)使用Block实现

    __weak typeof(self) weakself = self;

    //block先赋值,再使用
    girlFriends *gf = [girlFriends shareInstance];
    //[gf buyAnotherLadiesBackpackForMe]; //wrong write place
    gf.buyBlock = ^(NSString *goods){
        NSString *tempStr = [NSString stringWithFormat:@"%@❤️❤️❤️������",goods];
        [weakself.label4 setText:tempStr];
    };
    [gf buyAnotherLadiesBackpackForMe];

    if (timer.isValid == YES) {
        [timer invalidate];
    }

3.使用通知模式实现

    //tips:先注册观察者,再发送通知

    girlFriends *gf = [girlFriends shareInstance];
    //[gf buyAnyoneLadiesBackpackForMe];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buyLVAction:) name:@"buybag" object:nil];

    [gf buyAnyoneLadiesBackpackForMe];


-(void)dealloc{
    //记得释放通知的观察者对象
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"buybag" object:nil];
}
情景二:Block作为参数
girlFriends *gf = [girlFriends shareInstance];
    [gf buyMoreLadiesBackpackForMe:^float(int loveNumber) {
        //
        NSLog(@"520");
        float result = 520+(float)loveNumber/10000;
        NSLog(@"%.4f",(float)loveNumber/10000);
        NSString *tempStr = [NSString stringWithFormat:@"%.4f❤️❤️❤️������",result];
        [_label6 setText:tempStr];

        return result;

    }];

    if (timer.isValid == YES) {
        [timer invalidate];
    }

girlFriends.m
-(void)buyMoreLadiesBackpackForMe:(myLoveBlock2)ablock{
    float result = ablock(1314);
    NSLog(@"%.4f",result);

}
情景三:Block作为返回值

通过递归调用来体现以Block作为返回值的函数的调用和实现

调用
[self digui:3];
实现
- (int)digui:(int)number{
    if (number <= 2 && number > 0) {
        return number;
    } else {
        int tempResult = [self digui:number-1];
        return number*tempResult;
    }
}

调用
gf.setupTab5(3);
实现
- (int(^)(int))setupTab5
{
__weak typeof (self)weakSelf = self;
int(^block)(int) = ^(int a){
_recursiveResult2 *= a;
NSLog(@”%d – %d”, _recursiveResult2,a);
if (a>1) {
weakSelf.setupTab5(a-1);
//weakSelf setupTab5;
}
return _recursiveResult2;

};
return block;

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值