I'm comparing the memory footprint of delegate vs block in Objective-C, for solving a same problem. For example, there is a worker class who does some work:
// 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
The code is self-explanatory, in order to know when a work has been done, I can use either the delegate or block:
@implementation MyObject
- (void)workHasBeenDone
{
[self doCleanUp];
}
- (void)entryMethod
{
Worker *worker = [Worker new];
worker.delegate = self;
// or:
worker.block = ^{[self doCleanUp];};
[worker doTheWork];
}
@end
As far as I know, in the above code, self
as a delegate, is in memory; And the block
is copied on heap, but I'm not sure, which has better memory footprint?
Now I need a number of workers:
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,
...
};
In this case, block seems to be cleaner, but still, does it have better, same or worse memory footprint?
Thanks a lot!
A block is an ObjC object, so it comes with the same memory usage. You're on the right path thinking about multiple Worker
s — what happens if you want to do the same cleanup in response to all of them?
With a delegate:
workerA.delegate = workerB.delegate = workerC.delegate = self;
//...
- (void)workHasBeenDoneWithWorker:(Worker *)worker {
//...
}
Here you get three weak references to the same object, so no additional storage or ownership requirements. And the same workHasBeenDoneWithWorker:
method gets called three times. (Notice I changed it a little bit — it's good for a delegate method to know who called it, for exactly this reason: one object can be the delegate for multiple others, and it may want to know whose work it has been delegated.)
Now, with blocks:
workerA.block = workerB.block = workerC.block = ^{ [self doCleanUp]; };
Because your block is declared @property (copy)
, this gets you three copies of the block. Even though its source code is the same, the internal and captured state for each will be different. Also, there's no way (as declared) for the block to know whose work it's doing... and if you added a parameter to the block that references the Worker
it belongs to, you'll have to be careful about reference cycles. The memory usage difference is trivial, but the API architecture difference is more significant.
In general, delegates work well when:
And (completion-handler style) blocks work well when:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With