问题
Mailcore has a cool method that downloads an attachment and accepts a block as a parameter to return download progress:
- (CTCoreAttachment *)fetchFullAttachmentWithProgress:(CTProgressBlock)block;
where CTProgressBlock is defined as
typedef void (^CTProgressBlock)(size_t curr, size_t max);
so typically I would use it like so:
//AttachmentDownloader.m
int fileNum = x; // explained later
CTCoreAttachment* fullAttachment =
[attachment fetchFullAttachmentWithProgress:^(size_t curr, size_t max) {
NSLog(@"::: this is curr: %zu", curr);
NSLog(@"::: this is max: %zu\n\n", max);
}];
the problem is that this last method is called by my main UI class FileBucket.m
and this class is in turn fetching many attachments for many different UI elements in sequence. I would like this callback method to report back to FileBucket.m
which attachment this progress belongs to.. so in other words i want something along the lines of:
// FileBucket.m
[AttachmentDownloader runMultiple:attachmentTree
withProgress:^(size_t curr, size_t max, int fileNum) {
NSLog(@"::: this is curr: %zu", curr);
NSLog(@"::: this is max: %zu\n\n", max);
NSLog(@"::: this progress belongs to element %d", fileNum);
}];
I know this is hard to explain/illustrate.. one extra thing: AttachmentDownloader.m
is aware of which attachment this progress is about.. but it just wants to pass it back to FileBucket.m
every time the callback block is called.
回答1:
I don't know that class specifically, but in general any block "captures" variables used inside the block. So this should "just work":
int fileNum = x;
CTCoreAttachment* fullAttachment =
[attachment fetchFullAttachmentWithProgress:^(size_t curr, size_t max) {
// ..
NSLog(@"::: this progress belongs to element %d", fileNum);
}];
The block captures the value of the variable at the moment when the block is created.
(It would be slightly different if fileNum
is declared with the __block
modifier,
but that is probably not relevant to your problem.)
回答2:
the way I figured this out is by breaking it into two steps:
- implementing what I want through delegation
- converting the delegation into a block based approach.
and since this problem is kind of hard to explain by english, I figured it's best explained by sample code :)
Delegation Solution:
// AttachmentDownloader.m
+(void)runMultiple:(NSDictionary *)attachmentTree
withDelegate:(id<AttachmentDownloaderDelegate>)delegate {
..
CTCoreAttachment* fullAttachment =
[attachment fetchFullAttachmentWithProgress:^(size_t curr, size_t max) {
NSLog(@"::: this is curr: %zu", curr);
NSLog(@"::: this is max: %zu\n\n", max);
NSLog(@"::: this is attachment uid %@", [message uid]);
[delegate deliverProgressWithInfo:@{@"uid":[message uid],
@"curr":[NSNumber numberWithInt:curr],
@"max":[NSNumber numberWithInt:max]}];
}];
// FileBucket.m
[AttachmentDownloader runMultiple:attachmentTree withProgress:^(size_t curr, size_t max) {
NSLog(@"::: this is curr: %zu", curr);
NSLog(@"::: this is max: %zu\n\n", max);
} withDelegate:self];
// delegate method
-(void)deliverProgressWithInfo:(NSDictionary *)dict {
NSLog(@"filebucket: this is info being updated %@", dict);
}
Block Solution:
// AttachmentDownloader.m
+(void)runMultiple:(NSDictionary *)attachmentTree
withProgress:(void(^)(NSDictionary *))block {
..
CTCoreAttachment* fullAttachment =
[attachment fetchFullAttachmentWithProgress:^(size_t curr, size_t max) {
NSLog(@"::: this is curr: %zu", curr);
NSLog(@"::: this is max: %zu\n\n", max);
NSLog(@"::: this is attachment uid %@", [message uid]);
block(@{@"uid": [message uid],
@"curr": [NSNumber numberWithInt:curr],
@"max": [NSNumber numberWithInt:max]});
}];
// FileBucket.m
-(void)downloadSelectedAttachments {
NSDictionary* attachmentTree = [self getAttachmentTree];
[AttachmentDownloader runMultiple:attachmentTree withProgress:^(NSDictionary * dict) {
NSLog(@"filebucket: this is info being updated %@", dict);
}];
}
来源:https://stackoverflow.com/questions/17773067/how-to-add-an-extra-argument-to-a-block