2014-11-06 15 views
5

Tôi đang so sánh dấu chân bộ nhớ của đại biểu vs khối trong Mục tiêu-C, để giải quyết cùng một vấn đề. Ví dụ, có một lớp người lao động thực hiện một số công việc:ObjC: sử dụng bộ nhớ của đại biểu vs khối?

// 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 

Mã này là tự giải thích, để biết khi nào một công việc đã được thực hiện, tôi có thể sử dụng một trong hai đại biểu hoặc khối:

@implementation MyObject 

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

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

@end 

Theo như tôi biết, trong mã trên, self làm đại biểu, có trong bộ nhớ; Và block được sao chép trên heap, nhưng tôi không chắc chắn, có dấu chân bộ nhớ tốt hơn?

Bây giờ tôi cần một số công nhân:

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

Trong trường hợp này, khối có vẻ là sạch hơn, nhưng vẫn còn, nó có tốt hơn, tương tự hoặc tệ hơn bộ nhớ?

Cảm ơn rất nhiều!

+1

Cách duy nhất để biết là thử và đo lường. Các chi tiết cụ thể phụ thuộc vào các chi tiết thực hiện từng cách tiếp cận để thực hiện những gì bạn muốn làm – uchuugaka

Trả lời

9

Khối là đối tượng ObjC, vì vậy nó đi kèm với việc sử dụng bộ nhớ giống nhau. Bạn đang trên con đường bên phải suy nghĩ về nhiều Worker s - điều gì sẽ xảy ra nếu bạn muốn làm sạch cùng một phản ứng với tất cả chúng?

Với đại biểu:

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

//... 

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

Ở đây bạn có được ba tài liệu tham khảo yếu để cùng một đối tượng, vì vậy không lưu trữ hay sở hữu thêm yêu cầu. Và cùng một phương thức workHasBeenDoneWithWorker: được gọi ba lần. (Thông báo tôi đã thay đổi nó một chút - tốt cho phương pháp đại biểu để biết ai đã gọi nó, vì lý do chính xác này: một đối tượng có thể là đại biểu cho nhiều người khác, và có thể muốn biết công việc của họ đã được ủy nhiệm).

Bây giờ, với các khối:

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

Bởi vì khối của bạn được khai báo @property (copy), điều này giúp bạn ba bản sao của khối. Mặc dù mã nguồn của nó là như nhau, trạng thái bên trong và được capture cho mỗi mã sẽ khác nhau. Ngoài ra, không có cách nào (như được khai báo) cho khối để biết công việc của nó đang làm ... và nếu bạn thêm tham số vào khối tham chiếu đến Worker nó thuộc về, bạn sẽ phải cẩn thận về chu kỳ tham chiếu. Sự khác biệt về sử dụng bộ nhớ là không đáng kể, nhưng sự khác biệt về kiến ​​trúc API là quan trọng hơn.

Nhìn chung, các đại biểu làm việc tốt khi:

  • nhiều đối tượng ủy thác có thể chia sẻ các đại biểu cùng
  • phương pháp đại biểu cùng có thể được gọi nhiều lần cho đối tượng Delegating cùng

Và khối (kiểu xử lý hoàn thành) hoạt động tốt khi:

  • công việc sẽ được thực hiện một lần, khối sẽ được gọi một lần, và sau đó là khối sẽ bị loại bỏ
  • nhiệm vụ hoàn thành được gắn rất chặt chẽ với nhiệm vụ thiết lập rằng khả năng của một khối để nắm bắt tình trạng xung quanh rất có giá trị
+0

Câu trả lời hay, toàn diện (bình chọn). Tuy nhiên, một câu hỏi. Thiết kế đại biểu của bạn đặc biệt truyền điều mà ủy quyền cho đại biểu như là một phần của thiết kế giao thức. Mẫu đại biểu không làm điều đó "miễn phí". Tương tự, bạn có thể thiết kế khối phong cách trình xử lý hoàn thành chuyển vào đối tượng mà mã hoàn thành đang được thực thi. Để nói "... không có cách nào (như tuyên bố) cho khối để biết công việc của người đó đang làm ..." là lỗi của việc triển khai cụ thể, không phải là một hạn chế của mẫu thiết kế. –

+0

Do đó, vòng loại "được khai báo". Và lưu ý rằng nếu bạn thay đổi chữ ký khối của bạn để truyền đối tượng ủy nhiệm làm tham số, bạn phải xem ra các chu trình tham chiếu. – rickster

+0

"Mặc dù mã nguồn của nó giống nhau, trạng thái nội bộ và được ghi lại cho mỗi mã sẽ khác nhau." Tại sao họ lại khác? Bạn chỉ đánh giá một khối chữ một lần; trạng thái nên giống nhau. – newacct

0

Một khối mẫu gọi lại cho phép bạn kiểm soát nhiều hơn mối quan hệ quản lý bộ nhớ so với mẫu ủy nhiệm.

Với mẫu đại biểu, cho dù liên kết đại biểu là tham chiếu mạnh hay yếu được xác định trong khai báo lớp đang thực hiện ủy quyền (cho dù thuộc tính được khai báo là strong hoặc weak). Nó thường là weak. Đối tượng là đại biểu (đối tượng cha) không kiểm soát được thứ mà nó muốn.

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

Với một mô hình khối callback, lớp làm Delegating có một tham chiếu mạnh để khối, nhưng khối, được cung cấp bởi các đối tượng phụ huynh, có thể có hoặc là một tài liệu tham khảo mạnh hay yếu để đối tượng phụ huynh , có hiệu quả xác định mối quan hệ mạnh hoặc yếu giữa người ủy nhiệm và đối tượng cha. Nó có thể làm điều này bởi vì khối, thường được tạo bên trong mã của đối tượng cha, có thể chọn chụp self (đối tượng cha) hoặc mạnh mẽ (trực tiếp) hoặc yếu (bằng cách sử dụng biến số weakSelf).

Vì vậy, đối tượng cha, sử dụng lớp người ủy nhiệm này, có thể kiểm soát xem liên kết có mạnh hay yếu tùy thuộc vào yêu cầu thiết kế của trường hợp sử dụng cụ thể.

Parent object <----strong/weak---- block <----strong---- Delegator 
Các vấn đề liên quan