iOS块设计:带返回值的嵌套块?

iOS块设计:带返回值的嵌套块?,ios,objective-c,objective-c-blocks,Ios,Objective C,Objective C Blocks,我有一个委托回调方法,需要将数据(例如NSArray)返回给调用者 我可以从另一个区块调用中获取此数据。谁能帮我设计一个在这种情况下使用积木 我想出了这样的办法,但不确定这样做是否正确 NSArray* (^eventsForDate)(NSDate *) = ^(NSDate *date) { [[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) { return

我有一个委托回调方法,需要将数据(例如
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:
块函数,而不是
events fordate:

但是,需要注意的是:只有当
getEventsForDate:
dispatch
(或者它总是在
eventsForData
块的同一线程中运行)时,上述设计才会起作用

编辑:

如上所述,如果在
getEventsForDate:
中有
dispatch
,这并不总是像预期的那样工作。因为您不能保证C行将在A行和B行之后执行。这实际上取决于
getEventsForDate:
的工作方式。下面是另一个更好地说明问题的示例。没有a
sleep(1)
在代码底部,您可能会得到
结果
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行。有关更多详细信息,请参考此问题:

简而言之,您可以编写如下内容:

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;
};
void (^eventsForDate)(NSDate *) = ^void(NSDate *date) {
    [[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
        // Update UI and etc. 
    } onError:^(NSError *error) {
        // Update UI and etc. 
    }];
};
编辑2

但是,即使是上面的代码也可能对您有效。这听起来不是一个好主意。这是因为,如果
getEventsForDate:
被调度到后台线程,这意味着它非常慢,并且希望在后台执行。并且用semephore或其他任何东西阻塞主线程将破坏一切。因此,更好的方法仍然是在块中执行您想执行的任何操作,并永久删除
返回值

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;
};
void (^eventsForDate)(NSDate *) = ^void(NSDate *date) {
    [[DataManager sharedInstance] getEventsForDate:date onSuccess:^(NSArray *events) {
        // Update UI and etc. 
    } onError:^(NSError *error) {
        // Update UI and etc. 
    }];
};

其中有一些应该会有所帮助。您不能从块中返回任何内容,因此您只需在完成处理程序中调用
eventsForDate
。您当然可以从块中返回某些内容。它将返回给调用该块的人。在这种情况下,getEventsForDate中的某个地方:我希望会调用onSuccess或t他创建了一个错误的块,该调用将接收块返回的内容。问题是getEventsForDate:对该结果做了什么。谢谢Yuchen…如何确保所有这些都在同一个线程上运行?或者是否有更好的设计我可以尝试?好的,这不能用一行来解释。给我几分钟时间。我将更新我的答案。