2014-11-06 43 views
5

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

// 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, 
    ... 
}; 

在这种情况下,块似乎是清洁的,但尽管如此,它有更好的,相同或更糟糕的内存占用?

非常感谢!

+1

要知道的唯一方法就是尝试它并进行测量。具体细节取决于实施每种方法的细节来做你想做的事 – uchuugaka 2014-11-07 00:04:22

回答

9

块是一个ObjC对象,所以它具有相同的内存使用情况。你在正确的道路上思考多个Worker s - 如果你想对所有人做同样的清理,会发生什么?

与代理人:

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

//... 

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

在这里你会得到相同的对象具有三个弱引用,所以不需要额外的存储或所有权的要求。同样workHasBeenDoneWithWorker:方法被调用三次。 (注意我稍微改了一下 - 对于一个委托方法来说,知道是谁调用它是很好的,正是出于这个原因:一个对象可以是多个其他对象的委托,并且它可能想知道委派了哪些对象的工作。)

现在,随着块:

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

因为你的块声明@property (copy),这可以让你的块的三个副本。即使它的源代码是相同的,每个内部和捕获状态也会不同。此外,块没有办法(如声明)知道它正在做什么工作......并且如果您添加了一个参数给引用其所属的块的参数,则必须注意参考周期。内存使用差异是微不足道的,但API体系结构差异更为显着。

在一般情况下,代表工作以及时:

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

而且(完成处理程序样式)块可以很好地工作:

  • 工作将一次完成,该块将被调用一次,然后该块将被丢弃
  • 完成的任务是如此紧密联系在一起的安装任务,一个块来捕捉周围的状态的能力是有价值的
+0

好的,彻底的答案(投票)。不过,有一个狡猾的说法。作为协议设计的一部分,您的委托设计专门将委派给委托的事情传递给委托。代表模式不会“免费”。同样,您可以设计一个完成处理程序样式块,它传入正在执行完成代码的对象。要说“......没有办法(如声明的)让这个区块知道它在做什么工作......”是特定实现的缺点,而不是设计模式的限制。 – 2014-11-07 02:34:11

+0

因此“声明”限定符。另外请注意,如果您更改了块签名以将委托对象作为参数传递,则必须注意参考周期。 – rickster 2014-11-07 04:46:21

+0

“即使它的源代码是相同的,每个内部和捕获状态也会不同。”他们为什么会不一样?你只评估一个块文字一次;国家应该是一样的。 – newacct 2014-11-08 02:11:48

0

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

对于委托模式,无论委托链接是强还是弱参考,都是在进行委托的类的声明中确定的(无论该属性是否宣布为strongweak)。它通常是weak。作为委托对象(父对象)的对象无法控制它的意图。

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

与块回调模式,类做委派具有很强的参考块,但是块,这是由父对象提供,可以有一个强或弱参考父对象,这有效地决定了委托人与父对象之间的强弱关系。它可以这样做,因为通常在父对象代码中创建的块可以选择强烈(直接)或弱(通过使用weakSelf变量)捕获self(父对象)。

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

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