Функция, которая возвращает функцию

Как назначить и впоследствии вызвать функцию, которая возвращает функцию в локальную переменную в Objective-C?

ОБНОВИТЬ:

Я придумал следующее, но, боюсь, это все еще неправильно:

(void (^)()) (^loadedCallback) () = (void (^)()) ^(){
    @synchronized (synchronizer) {
        semaphore++;
    }
      return Block_copy(^{
          @synchronized (synchronizer) {
              semaphore--;
              if (semaphore == 0) {
                  onAllLoaded();
              }
          }
      }); };

person mgamer    schedule 13.07.2011    source источник
comment
Возможно, вы захотите изучить dispatch_semaphores, которые обеспечивают быстрый интерфейс без блокировки семафоров.   -  person zneak    schedule 13.07.2011


Ответы (1)


Во-первых, вам нужно понять синтаксис объявления указателя функции. То же самое для блоков, за исключением того, что это ^ вместо *.

Затем вам нужно создать блок, вернуть его копию и присвоить ее правильно объявленной переменной.

typedef NSArray* (^my_block_type_t)(int, float);

my_block_type_t createBlock()
{
    my_block_type_t block = ^(int a, float b)
    {
        return [NSArray array];
    };
    return Block_copy(block);
}

/* snip */
my_block_type_t theBlock = createBlock();
theBlock();
Block_release(theBlock);

EDIT для исправления OP: typedef обычно используются для облегчения чтения кода. В случае блоков и указателей на функции это также упрощает написание. Существует встроенный typedef (dispatch_block_t) для блоков, которые не принимают аргументов и возвращают void; вы должны использовать его. Вы также должны сделать столько typedef, сколько вам нужно, чтобы избежать использования уродливых указателей функций синтаксиса объявления, которые в противном случае будут принудительно применяться в вашем коде.

typedef dispatch_block_t (^block_creator_t)();

block_creator_t loadedCallback = ^{
    @synchronized (synchronizer)
    {
        semaphore++;
    }

    dispatch_block_t result = ^{
        @synchronized (synchronizer)
        {
            semaphore--;
            if (semaphore == 0)
                onAllLoaded();
        }
    };

    return Block_copy(result);
};
person zneak    schedule 13.07.2011
comment
Разве нельзя использовать Block_copy и Block_release? Я знаю, что блоки имеют указатель isa и могут быть отправлены в сообщения, это похоже на деталь реализации. - person Joe; 13.07.2011
comment
@ Джо, это в основном (плохая?) привычка с моей стороны. Я изменю это на Block_copy/Block_release. - person zneak; 13.07.2011