ios - 总是将 self 的弱引用传递到 ARC 中的 block 中?

我对 Objective-C 中的 block 使用有点困惑。我目前使用 ARC,我的应用程序中有很多 block ,目前总是引用 self 而不是它的弱引用。这可能是这些 block 保留 self 并防止它被释放的原因吗?问题是,我是否应该始终在 block 中使用 selfweak 引用?

-(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);
}

ProcessOperation.m

-(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);
    }
}

最佳答案

不要把注意力集中在讨论的 strongweak 部分。而是专注于循环部分。

A retain cycle 是当对象 A 保留对象 B,并且对象 B 保留对象 A 时发生的循环。在这种情况下,如果任一对象被释放:

  • 对象 A 不会被释放,因为对象 B 持有对它的引用。
  • 但只要对象 A 有对它的引用,对象 B 就永远不会被释放。
  • 但对象 A 永远不会被释放,因为对象 B 持有对它的引用。
  • 无限

因此,这两个对象将在程序的生命周期内一直在内存中徘徊,即使如果一切正常,它们应该被释放。

所以,我们担心的是保留循环,而创建这些循环的 block 本身并没有什么。这不是问题,例如:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

block 保留self,但self不保留 block 。如果释放其中一个或另一个,则不会创建循环,并且会按应有的方式释放所有内容。

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

//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) 具有对 block 的显式 strong 引用。并且该 block 具有对 self隐式 强引用。这是一个循环,现在两个对象都不会被正确释放。

因为在这种情况下,self 根据定义已经有一个对 block 的strong引用,通常最容易解决对 self 进行显式弱引用以供 block 使用:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

但这不应该是您在处理调用 self 的 block 时遵循的默认模式!这应该只用于打破 self 和 block 之间的保留循环。如果你在任何地方都采用这种模式,你就会冒着将 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];
}];

https://stackoverflow.com/questions/20030873/

相关文章:

objective-c - 编译警告 : no rule to process file for a

objective-c - UILabel中如何控制行距

ios - 解释 iOS7 中自动调整 ScrollView 插入、扩展布局包含不透明条、边缘For

ios - 单个 UILabel 中的粗体和非粗体文本?

objective-c - Xcode 6 中未创建 Swift 到 Objective-C hea

ios - 使用 Storyboard 以编程方式设置初始 View Controller

iOS - 从 ViewController 调用 App Delegate 方法

iphone - 如何比较两个 NSDates : Which is more recent?

ios - UIView无限360度旋转动画?

ios - 检测设备是否为 iPhone X