Có vẻ như bạn muốn liên lạc với một lớp tồn tại mà được thiết kế để có một đối tượng đại biểu. Có một số cách tiếp cận, bao gồm:
- sử dụng danh mục để thêm các biến thể dựa trên khối của phương pháp thích hợp;
- sử dụng lớp dẫn xuất để thêm các biến thể dựa trên khối; và
- viết một lớp thực hiện giao thức và gọi các khối của bạn.
Dưới đây là một cách để thực hiện (3). Trước tiên, hãy giả sử SomeObject của bạn là:
@protocol SomeObjectDelegate
@required
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
@interface SomeObject : NSObject
{
}
+ (void) testCallback:(id<SomeObjectDelegate>)delegate;
@end
@implementation SomeObject
+ (void) testCallback:(id<SomeObjectDelegate>)delegate
{
[delegate stuffDone:[NSNumber numberWithInt:42]];
[delegate stuffFailed];
}
@end
vì vậy chúng tôi có một số cách để kiểm tra - bạn sẽ có một SomeObject thực.
Bây giờ xác định một lớp mà thực hiện giao thức và kêu gọi khối cung cấp của bạn:
#import "SomeObject.h"
typedef void (^StuffDoneBlock)(id anObject);
typedef void (^StuffFailedBlock)();
@interface SomeObjectBlockDelegate : NSObject<SomeObjectDelegate>
{
StuffDoneBlock stuffDoneCallback;
StuffFailedBlock stuffFailedCallback;
}
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
- (void)dealloc;
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
// protocol
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
lớp này giúp tiết kiệm các khối bạn vượt qua trong và gọi họ là để đáp ứng với callbacks giao thức. Việc thực hiện rất đơn giản:
@implementation SomeObjectBlockDelegate
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
if (self = [super init])
{
// copy blocks onto heap
stuffDoneCallback = Block_copy(done);
stuffFailedCallback = Block_copy(fail);
}
return self;
}
- (void)dealloc
{
Block_release(stuffDoneCallback);
Block_release(stuffFailedCallback);
[super dealloc];
}
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
return (SomeObjectBlockDelegate *)[[[SomeObjectBlockDelegate alloc] initWithOnDone:done andOnFail:fail] autorelease];
}
// protocol
- (void)stuffDone:(id)anObject
{
stuffDoneCallback(anObject);
}
- (void)stuffFailed
{
stuffFailedCallback();
}
@end
Điều duy nhất bạn cần phải nhớ là để Block_copy() các khối khi khởi tạo và Block_release() chúng sau này - điều này là do khối được stack giao và đối tượng của bạn có thể sống lâu hơn việc tạo của nó ngăn xếp khung; Block_copy() tạo một bản sao trong heap.
Bây giờ bạn có thể tất cả các phương pháp đại biểu dựa trên đi qua nó khối:
[SomeObject testCallback:[SomeObjectBlockDelegate
someObjectBlockDelegateWithOnDone:^(id anObject) { NSLog(@"Done: %@", anObject); }
andOnFail:^{ NSLog(@"Failed"); }
]
];
Bạn có thể sử dụng kỹ thuật này để quấn khối đối với bất kỳ giao thức.
ARC Phụ Lục
Để đối phó với những nhận xét: để làm cho ARC này tương thích chỉ loại bỏ các cuộc gọi đến Block_copy()
rời khỏi nhiệm vụ trực tiếp:
stuffDoneCallback = done;
stuffFailedCallback = fail;
và loại bỏ các phương pháp dealloc
. Bạn cũng có thể thay đổi Blockcopy
thành copy
, tức là stuffDoneCallback = [done copy];
và đây là những gì bạn có thể giả định là cần thiết để đọc tài liệu ARC. Tuy nhiên nó không phải là nhiệm vụ là một biến mạnh khiến ARC giữ lại giá trị được gán - và giữ lại một khối ngăn xếp sao chép nó vào đống. Do đó, mã ARC được tạo ra có cùng kết quả có hoặc không có copy
.
bạn có thể giải thích phần này với ARC không? stuffDoneCallback = Block_copy (đã hoàn thành); stuffFailedCallback = Block_copy (không thành công); Nó nói với tôi, rằng nó cần một cây cầu đúc. – zeiteisen
@zeiteisen - Câu hỏi hay. Bạn có thể biết câu trả lời ngay bây giờ, xin lỗi tôi chưa bao giờ thấy nhận xét. Nhưng đối với khách truy cập trong tương lai tôi đã thêm một phụ lục. – CRD