ObjC:委托与块的内存使用情况?

时间:2014-11-06 23:42:22

标签: ios objective-c delegates objective-c-blocks

我正在比较Objective-C中委托与块的内存占用,以解决同样的问题。例如,有一个工人阶级做了一些工作:

// delegate
@protocol WorkerDelegate : NSObject
- (void)workHasBeenDone;
@end

// block
typedef void (^WorkerBlock)();

@interface Worker : NSObject

@property (nonatomic, weak) id<WorkerDelegate> delegate;

@property (nonatomic, copy) WorkerBlock block;

- (void)doTheWork;

@end

代码是不言自明的,为了知道工作何时完成,我可以使用委托或块:

@implementation MyObject

- (void)workHasBeenDone
{
    [self doCleanUp];
}

- (void)entryMethod
{
    Worker *worker = [Worker new];
    worker.delegate = self;
    // or:
    worker.block = ^{[self doCleanUp];};
    [worker doTheWork];
}

@end

据我所知,在上面的代码中,作为委托的self在内存中;并且block被复制到堆上,但我不确定,哪个内存占用更好?

现在我需要一些工人:

Worker *workerA = ... // created and set delegate OR block for completion notification
Worker *workerB = ... // created and set delegate OR block for completion notification
Worker *workerC = ... // created and set delegate OR block for completion notification
...

NSDictionary *workers = @{
    "jobA": workerA,
    "jobB": workerB,
    ...
};

在这种情况下,块似乎更清晰,但是,它是否有更好,相同或更差的内存占用?

非常感谢!

2 个答案:

答案 0 :(得分:10)

块是一个ObjC对象,因此它具有相同的内存使用量。你正在思考多个Worker的正确道路 - 如果你想对所有这些做出同样的清理会怎么样?

代表:

workerA.delegate = workerB.delegate = workerC.delegate = self;

//...

- (void)workHasBeenDoneWithWorker:(Worker *)worker {
    //...
}

这里有三个对同一对象的弱引用,因此没有额外的存储或所有权要求。并且相同的workHasBeenDoneWithWorker:方法被调用三次。 (注意我改变了一点 - 委托方法知道谁调用它是有好处的,正是因为这个原因:一个对象可以是多个其他对象的委托,它可能想知道它的工作是什么被委派了。)

现在,使用块:

workerA.block = workerB.block = workerC.block = ^{ [self doCleanUp]; };

因为您的块被声明为@property (copy),所以这会获得该块的三个副本。即使它的源代码相同,每个的内部和捕获状态也会不同。此外,该块无法(如声明的那样)知道它正在做什么工作......并且如果您向引用其所属的Worker的块添加了参数,你必须小心参考周期。内存使用差异微不足道,但API架构差异更为显着。

一般来说,代表在以下情况下工作良好:

  • 多个委派对象可能共享同一个委托
  • 对于同一委托对象,可能会多次调用相同的委托方法

并且(完成处理程序样式)块在以下情况下运行良好:

  • 工作将完成一次,块将被调用一次,然后块将被丢弃
  • 完成任务与设置任务密切相关,以至于块捕获周围状态的能力是有价值的

答案 1 :(得分:0)

块回调模式使您可以比委托模式更好地控制内存管理关系。

使用委托模式,委托链接是强引用还是弱引用是在执行委托的类的声明中确定的(属性是声明为strong还是weak)。通常是weak。作为委托的对象(父对象)无法控制它想要的内容。

Parent object <----weak---- Delegator

使用块回调模式,执行委托的类具有对块的强引用,但是由父对象提供的块可以具有对父对象的强引用或弱引用,这有效地确定委托者和父对象之间的强弱关系。它可以这样做,因为通常在父对象的代码内创建的块可以选择强烈(直接)或弱地(通过使用self变量)捕获weakSelf(父对象)

因此,使用此委托者类的父对象可以根据特定用例的设计要求控制链接是强还是弱。

Parent object <----strong/weak---- block <----strong---- Delegator