美文网首页iOS Block
关于block使用的一些总结

关于block使用的一些总结

作者: 秋意阑珊 | 来源:发表于2018-04-24 19:37 被阅读6次

网上已经有很多讨论block底层实现原理的文章,这里不讨论实现,只讨论block使用中的一些问题。

一、声明block属性时应该使用什么关键字?

答案:copy

以下内容翻译自官方文档:
定义一个跟踪block的属性的语法:

@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

注意:你应该指定copy作为属性关键字,因为块需要被拷贝以跟踪它在原始范围外捕获的状态。由于使用自动引用计数时(Automatic Reference Counting)这是自动发生的,所以你不需要担心这些,但是属性关键字的最佳做法是展示结果行为。更多关于block的信息,参阅Blocks Programming Topics

上面这一段翻译的官方文档原文地址:Programming with Objective-C/Working with Blocks

注意:copy对属性也是强引用,只不过这个强引用指向的是赋值给属性的那个对象的一份拷贝。官方文档copy关键字的使用有详细说明,详情参阅文档《Programming with Objective-C》中Encapsulating Data主题的Copy Properties Maintain Their Own Copies章节

二、block循环引用

循环引用的产生

以下内容翻译自官方文档:
block对任何捕获的对象保持强应用,包括self,这意味着如果一个对象对一个捕获了self的block保持了copy属性(上面第一个问题中解释过,官方文档建议block属性使用copy关键字,且copy属性self对属性也是强引用,详情请翻看问题一):

@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
@implementation XYZBlockKeeper
- (void)configureBlock {
    self.block = ^{
        [self doSomething];// 捕获对self的强引用(capturing a strong reference to self)
                               // 创建了一个强引用循环(creates a strong reference cycle)
    };
}
...
@end

解决方法:
避免这个问题的最好方法是捕获对self的弱引用,如下:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // 捕获弱引用以避免循环引用(capture the weak reference to avoid the reference cycle)
    }
}

通过捕获指向self的弱指针,block就不会与XYZBlockKeeper对象保持强关系。如果对象在block调用前解除分配,weakSelf指针将被简单地置为nil。

官方文档地址:Programming with Objective-C/Working with Blocks

调用的方法中有block参数,会不会导致循环引用?

问题描述:如果self或self.property调用的方法中有个block参数,在这个block参数中使用了self,会不会导致循环引用?
这里的方法其实有两种情况:self中的方法和self中属性对象中的方法

self自己的方法使用block作为参数,这个block中使用了self,会不会导致循环引用?

代码如下:

- (void)doSomething {
    [self testWithBlock:^{
        [self testMethod];
    }];
}

- (void)testWithBlock:(void(^)())block {
    block();
}

- (void)testMethod {
    NSLog(@"test");
}

答案:此时block只是一个临时变量,self并没有对其持有,所有不会产生循环引用。

self的属性对象中的方法,使用block作为参数,block中使用了self,会不会产生循环引用?

这里也有两种情况:1、属性对象持有了传入的block参数 2、属性对象未持有传入的block参数

1、属性对象持有了传入的block参数

代码如下:

#import <Foundation/Foundation.h>
typedef void (^BlockType)(void);
@interface AbcObject : NSObject
- (void)methodWithBlock:(BlockType)block;
@end

#import "AbcObject.h"
@interface AbcObject()
//不作为公有属性,而是在对外方法接口中把Block传进来
@property (nonatomic, copy) BlockType block;
@end

@implementation AbcObject
- (void)methodWithBlock:(BlockType)block {
    //self.block留待后面其他地方异步调用
    //会产生循环引用
    self.block = block;

    //比如,发起一个异步请求
    //...
}

//比如是在一个请求的回调中执行刚才保存的block
- (void)completionDelegate {
    //调用刚才保存的block
    if (self.block) {
        self.block();
    }
}
@end
#import "ViewController.h"
#import "AbcObject.h"
@interface ViewController ()
@property (nonatomic, strong) AbcObject *abcObject;
@property (nonatomic, copy) NSString *str;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.str = @"haha";
    
    self.abcObject = [[AbcObject alloc] init];
    [self.abcObject configurePersonBlock:^{
        NSLog(@"printf str:%@", self.str);
        //解决问题的办法是block中使用weakSelf
    }];
]}
@end

如上面的例子,这里也有两种情况,如果传入abcObject对象的block参数被abcObject对象作为属性存储起来以备其他地方的异步调用,这种情况self持有了person,person又持有了传入的block,block中又引用了self,间接产生了循环引用。

2、属性对象未持有传入的block参数

如果上面的代码改一下,methodWithBlock中不用属性持有传入的block(其余代码不变):

#import <Foundation/Foundation.h>
typedef void (^ BlockType)(void);
@interface AbcObject : NSObject
- (void)methodWithBlock:(BlockType)block;
@end

#import "AbcObject.h"
@interface AbcObject()
@end

@implementation AbcObject
- (void)methodWithBlock:(BlockType)block {
    //做其他事情
    //...

    //不会产生循环引用
    if (block) {
        block();
    }
}
@end

则不会产生循环引用。

相关文章

  • 关于block使用的一些总结

    网上已经有很多讨论block底层实现原理的文章,这里不讨论实现,只讨论block使用中的一些问题。 一、声明blo...

  • Objective-C Block Part2 - 实现原理

    Block 的本质 在 Objective-C Block Part1 中总结了 Block 的一些使用规则,但...

  • iOS进阶-深度学习block原理

    目录 基本声明使用总结 block在ARC、MRC下内存方式 使用block遇到的坑 更深次的看block的本质 ...

  • OC block 原理总结

    本文重点总结 OC block 的原理,并带上一些例子,不讨论 block 的写法和应用。 block 的本质总结...

  • block,注册监听,委托协议和KVO

    总结 IOS中关于信息传递过程中经常会使用block,委托代理,NSNotification,KVO进行调用,但是...

  • 关于block总结

    关于block总结 block有三种: NSGlobalBlock静态区(全局区)block,这是一种特殊的blo...

  • Block使用总结

    Block和函数很像,具有如下特性: 可以保存代码 有返回值 有形参 调用方式一样 使用的形式举例:1)带参数的形...

  • Block 使用总结

    Block 内存管理: Block 内存主要分派到 NSGlobalBlock(data area),NSMall...

  • Block使用总结

    void (^mutiplayBlock)(NSString *) = ^(NSString *str) {NSL...

  • block使用总结

    1.block使用步骤: 1>.有两个控制器,主动传值或者提供方法的控制器A,接受值的控制器B2>.让A控制器ty...

网友评论

    本文标题:关于block使用的一些总结

    本文链接:https://www.haomeiwen.com/subject/ejopcftx.html