为了账号安全,请及时绑定邮箱和手机立即绑定

总是在ARC中将自身的弱引用传递给块吗?

总是在ARC中将自身的弱引用传递给块吗?

iOS
吃鸡游戏 2019-11-03 04:04:26
我对Objective-C中的块用法有些困惑。我当前使用的是ARC,我的应用程序中有很多块,当前总是引用self而不是其弱引用。这可能是这些块保留self并阻止其分配的原因吗?问题是,我应该始终在块中使用的weak引用self吗?-(void)handleNewerData:(NSArray *)arr{    ProcessOperation *operation =    [[ProcessOperation alloc] initWithDataToProcess:arr                                         completion:^(NSMutableArray *rows) {        dispatch_async(dispatch_get_main_queue(), ^{            [self updateFeed:arr rows:rows];        });    }];    [dataProcessQueue addOperation:operation];}ProcessOperation.h@interface ProcessOperation : NSOperation{    NSMutableArray *dataArr;    NSMutableArray *rowHeightsArr;    void (^callback)(NSMutableArray *rows);}流程操作-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{    if(self =[super init]){        dataArr = [NSMutableArray arrayWithArray:data];        rowHeightsArr = [NSMutableArray new];        callback = cb;    }    return self;}- (void)main {    @autoreleasepool {        ...        callback(rowHeightsArr);    }}
查看完整描述

3 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

这不仅有助于把重点放在strong或weak讨论的一部分。而是专注于循环部分。


保留周期是当对象A保留对象B 而对象B保留对象A 时发生的循环。在这种情况下,如果释放了任何一个对象,则:


因为对象B拥有对它的引用,所以不会释放对象A。

但是,只要对象A引用了对象B,就永远不会释放它。

但是对象A永远不会被释放,因为对象B拥有对它的引用。

广告无限

因此,即使在一切正常的情况下,这两个对象也应该在程序的生命周期内徘徊,即使它们在一切正常的情况下也应该被释放。


因此,我们担心的是保留周期,而创建这些周期的块本身没有任何问题。这不是问题,例如:


[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){

   [self doSomethingWithObject:obj];

}];

该块保留self,但self不保留该块。如果释放一个或另一个,则不会创建任何循环,并且一切都将按应有的方式释放。


您遇到麻烦的地方是这样的:


//In the interface:

@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);


//In the implementation:

[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {

  [self doSomethingWithObj:obj];     

}];

现在,您的对象(self)具有strong对该块的显式引用。并且该块具有对的隐式强引用self。这是一个周期,现在两个对象都不会被正确释放。


因为在这样的情况下,self 根据定义,已经有strong对该块的引用,所以通常最容易解决的方法self是为该块使用一个显式的弱引用:


__weak MyObject *weakSelf = self;

[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {

  [weakSelf doSomethingWithObj:obj];     

}];

但这不应该是您在处理调用块时遵循的默认模式self!这仅应用于打破在self和block之间的保留循环。如果要在所有地方都采用这种模式,则冒着将块传递给在self释放后执行的操作的风险。


//SUSPICIOUS EXAMPLE:

__weak MyObject *weakSelf = self;

[[SomeOtherObject alloc] initWithCompletion:^{

  //By the time this gets called, "weakSelf" might be nil because it's not retained!

  [weakSelf doSomething];

}];



查看完整回答
反对 回复 2019-11-04
?
温温酱

TA贡献1752条经验 获得超4个赞

您不必总是使用弱引用。如果您的块没有保留,而是被执行然后丢弃,则可以强烈地捕获自身,因为它不会创建保留周期。在某些情况下,您甚至希望该块保留自身,直到该块完成为止,这样它才不会过早地解除分配。但是,如果您强烈捕获该块,并在捕获自身内部,则会创建一个保留周期。

查看完整回答
反对 回复 2019-11-04
?
慕容708150

TA贡献1831条经验 获得超4个赞


但这不应该是您在处理称为self的块时遵循的默认模式!这仅应用于打破在self和block之间的保留循环。如果要在所有地方都采用这种模式,则冒着将块传递给在释放self之后执行的操作的风险。


//SUSPICIOUS EXAMPLE:

__weak MyObject *weakSelf = self;

[[SomeOtherObject alloc] initWithCompletion:^{

  //By the time this gets called, "weakSelf" might be nil because it's not  retained!

  [weakSelf doSomething];

}];

为了克服这个问题,可以weakSelf在块内部定义一个强引用:


__weak MyObject *weakSelf = self;

[[SomeOtherObject alloc] initWithCompletion:^{

  MyObject *strongSelf = weakSelf;

  [strongSelf doSomething];

}];



查看完整回答
反对 回复 2019-11-04
  • 3 回答
  • 0 关注
  • 439 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信