iOS 块设计:具有 Return 值的嵌套块?
iOS Block Design: Nested Blocks With Return Values?
我有一个委托回调方法需要 return 数据(Ex NSArray
)给调用者。
我可以从另一个块调用中获取此数据。谁能帮我设计一下,在这种情况下使用块。
我想到了类似的方法,但不确定这样做是否正确。
NSArray* (^eventsForDate)(NSDate *) = ^(NSDate *date) {
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
return events; //Obviously this doesn't work. Need help here.
} onError:^(NSError *error) {
return @[];
}];
};
//Delegate call back
- (NSArray *) calendarEventsForDate:(NSDate *) date
{
return eventsForDate(date);
}
所以你要找的或多或少是以下内容。
NSArray* (^eventsForDate)(NSDate *) = ^NSArray*(NSDate *date) {
__block NSArray *result = nil;
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
result = events; // Line A
} onError:^(NSError *error) {
result = @[]; // Line B
}];
return result; // Line C
};
A行和B行不能使用return
的原因代码)是您返回 onSuccess:
块函数和 onError:
块函数而不是 eventsForDate:
。
然而,一个重要的注意事项:只有当你的 getEventsForDate:
不 dispatch
(或者它总是在 eventsForData
块的同一个线程中运行时,以上设计才会起作用。
编辑:
如上所述,如果您的 getEventsForDate:
中有 dispatch
,这将不会总是按预期工作。因为你不能保证C行会在A行和B行之后执行。这实际上取决于 getEventsForDate:
的工作方式。下面再举一个例子来更好地说明问题。如果代码底部没有 sleep(1)
,您将 可能 得到 result
作为 nil
;使用 sleep(1)
,您将 可能 得到 @[@"A"]
。
- (void)getEventsForDate:(NSDate *)date
onSuccess:(void(^)(NSArray *))sucessBlock
onError:(void(^)(NSError *))errorBlock
{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(q, ^{
sucessBlock(@[@"A"]);
});
// sleep(1);
}
所以你真正需要做的是阻塞C行并至少等到A行或 B 行被执行。详情请参考这个问题:
How do I wait for an asynchronously dispatched block to finish?
简而言之,你可以这样写:
NSArray* (^eventsForDate)(NSDate *) = ^NSArray*(NSDate *date) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block NSArray *result = nil;
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
result = events;
dispatch_semaphore_signal(sema);
} onError:^(NSError *error) {
result = @[@"B"];
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
return result;
};
编辑 2
但是,即使是上面的代码也可能对您有用。去这听起来不是个好主意。那是因为,如果 getEventsForDate:
被分派到后台线程,则意味着它非常慢并且希望在后台执行。并用信号量或其他任何东西阻塞你的主线程会毁了一切。因此,更好的方法仍然是在块中做您想做的任何事情,并永久删除 return
。类似于以下内容:
void (^eventsForDate)(NSDate *) = ^void(NSDate *date) {
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
// Update UI and etc.
} onError:^(NSError *error) {
// Update UI and etc.
}];
};
我有一个委托回调方法需要 return 数据(Ex NSArray
)给调用者。
我可以从另一个块调用中获取此数据。谁能帮我设计一下,在这种情况下使用块。
我想到了类似的方法,但不确定这样做是否正确。
NSArray* (^eventsForDate)(NSDate *) = ^(NSDate *date) {
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
return events; //Obviously this doesn't work. Need help here.
} onError:^(NSError *error) {
return @[];
}];
};
//Delegate call back
- (NSArray *) calendarEventsForDate:(NSDate *) date
{
return eventsForDate(date);
}
所以你要找的或多或少是以下内容。
NSArray* (^eventsForDate)(NSDate *) = ^NSArray*(NSDate *date) {
__block NSArray *result = nil;
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
result = events; // Line A
} onError:^(NSError *error) {
result = @[]; // Line B
}];
return result; // Line C
};
A行和B行不能使用return
的原因代码)是您返回 onSuccess:
块函数和 onError:
块函数而不是 eventsForDate:
。
然而,一个重要的注意事项:只有当你的 getEventsForDate:
不 dispatch
(或者它总是在 eventsForData
块的同一个线程中运行时,以上设计才会起作用。
编辑:
如上所述,如果您的 getEventsForDate:
中有 dispatch
,这将不会总是按预期工作。因为你不能保证C行会在A行和B行之后执行。这实际上取决于 getEventsForDate:
的工作方式。下面再举一个例子来更好地说明问题。如果代码底部没有 sleep(1)
,您将 可能 得到 result
作为 nil
;使用 sleep(1)
,您将 可能 得到 @[@"A"]
。
- (void)getEventsForDate:(NSDate *)date
onSuccess:(void(^)(NSArray *))sucessBlock
onError:(void(^)(NSError *))errorBlock
{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(q, ^{
sucessBlock(@[@"A"]);
});
// sleep(1);
}
所以你真正需要做的是阻塞C行并至少等到A行或 B 行被执行。详情请参考这个问题:
How do I wait for an asynchronously dispatched block to finish?
简而言之,你可以这样写:
NSArray* (^eventsForDate)(NSDate *) = ^NSArray*(NSDate *date) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block NSArray *result = nil;
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
result = events;
dispatch_semaphore_signal(sema);
} onError:^(NSError *error) {
result = @[@"B"];
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
return result;
};
编辑 2
但是,即使是上面的代码也可能对您有用。去这听起来不是个好主意。那是因为,如果 getEventsForDate:
被分派到后台线程,则意味着它非常慢并且希望在后台执行。并用信号量或其他任何东西阻塞你的主线程会毁了一切。因此,更好的方法仍然是在块中做您想做的任何事情,并永久删除 return
。类似于以下内容:
void (^eventsForDate)(NSDate *) = ^void(NSDate *date) {
[[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
// Update UI and etc.
} onError:^(NSError *error) {
// Update UI and etc.
}];
};