я могу поместить объективный-C селектор в структуру?

Думайте, что Вы читаете Arabii или иврит: читайте из верхней части страницы, справа налево к нижней части.; P хорошая вещь об этом "правиле" то, что это работает на 3 версии значения также: top right-and-left bottom

На самом деле, я также думал, что было трудно помнить, но как только я обнаружил, что это было направление часов, это было легче.

7
задан Keavon 18 May 2014 в 05:54
поделиться

3 ответа

Этот ответ объясняет, почему «элемент инициализатора не является постоянным» .

В следующем примере:

SEL theSelector; // Global variable

void func(void) {
  theSelector = @selector(constantSelector:test:);
}

Компилируется примерно так для Архитектура i386 :

  .objc_meth_var_names
L_OBJC_METH_VAR_NAME_4:
  .ascii "constantSelector:test:\0"

  .objc_message_refs
  .align 2
L_OBJC_SELECTOR_REFERENCES_5:
  .long   L_OBJC_METH_VAR_NAME_4

Эта часть определяет две локальные (в терминах ассемблерного кода) «переменные» (на самом деле метки), L_OBJC_METH_VAR_NAME_4 и L_OBJC_SELECTOR_REFERENCES_5 . Текст .objc_meth_var_names и .objc_message_refs , непосредственно перед метками «переменная», сообщает ассемблеру, в какую часть объектного файла поместить «следующий материал». Разделы имеют значение для компоновщика. L_OBJC_SELECTOR_REFERENCES_5 изначально установлен на адрес L_OBJC_METH_VAR_NAME_4 .

Во время загрузки выполнения, section.

  • Каждая запись изначально устанавливается как указатель на строку 0 с завершением C .
  • В нашем примере указатель изначально установлен на адрес L_OBJC_METH_VAR_NAME_4 , который содержит строку ASCII C "constantSelector: test:" .
  • Затем он выполняет sel_registerName ("constantSelector: test:") и сохраняет возвращенное значение в L_OBJC_SELECTOR_REFERENCES_5 . Компоновщик, который знает детали частной реализации, может не вызывать sel_registerName () буквально.
  • По сути, компоновщик выполняет это во время загрузки для нашего примера:

    L_OBJC_SELECTOR_REFERENCES_5 = sel_registerName("constantSelector:test:");
    

    Вот почему «элемент инициализатора не является постоянным» - элемент инициализатора должен быть постоянным во время компиляции. Фактически значение неизвестно, пока программа не начнет выполняться. Даже в этом случае ваши объявления struct хранятся в другом разделе компоновщика, разделе .data . Компоновщик знает только, как обновить значения SEL в разделе .objc_message_refs , и нет способа «скопировать» вычисленное во время выполнения значение SEL из .objc_message_refs в произвольное место в .data .

    Исходный код C ...

    theSelector = @selector(constantSelector:test:);
    

    ... становится:

      movl    L_OBJC_SELECTOR_REFERENCES_5, %edx // The SEL value the linker placed there.
      movl    L_theSelector$non_lazy_ptr, %eax   // The address of theSelector.
      movl    %edx, (%eax)                       // theSelector = L_OBJC_SELECTOR_REFERENCES_5;
    

    Поскольку компоновщик выполняет всю свою работу до выполнения программы, L_OBJC_SELECTOR_REFERENCES_5 содержит то же значение, которое вы получили бы, если бы вызывали sel_registerName ("constantSelector: test:") :

    theSelector = sel_registerName("constantSelector:test:");
    

    Разница в том, что это вызов функции, и функция должна выполнить фактическую работу по поиску селектора, если он уже зарегистрирован, или пройти процесс выделения нового значения SEL . зарегистрировать селектор. Это значительно медленнее, чем просто загрузка постоянного значения. Хотя это «медленнее», но позволяет передавать произвольную строку C . Это может быть полезно, если:

    • Селектор неизвестен во время компиляции.
    • Селектор не известен до тех пор, пока не будет вызван sel_registerName () .
    • Вам необходимо динамически изменять селектор во время выполнения.

    Все селекторы должны проходить через sel_registerName () , который регистрирует каждый SEL ровно один раз. Это имеет то преимущество, что везде для любого селектора имеется ровно одно значение. SEL , хотя и является частной деталью реализации, «обычно» представляет собой просто указатель char * на копию строкового текста селекторов C .

    Теперь вы знаете. . А знание - это половина дела!

    SEL «обычно» просто char * указатель на копию селекторов C текст строки.

    Теперь вы знаете. А знание - это половина дела!

    SEL «обычно» просто char * указатель на копию селекторов C текст строки.

    Теперь вы знаете. А знание - это половина дела!

    23
    ответ дан 6 December 2019 в 06:50
    поделиться

    Как насчет:

    struct menuActions {
       CGRect rect;
       const char *action;
    };
    
    struct menuActions someMenuRects[] = {
       { { { 0, 0 }, {320, 60 } }, "doSomething" },
       { { { 0, 60}, {320, 50 } }, "doSomethingElse" },
    };
    

    Во время выполнения зарегистрируйте селекторы:

    int numberOfActions = 2;
    for (int i=0; i < numberOfActions; i++)
       NSLog (@"%s", sel_registerName(someMenuRects[i].action));
    

    Вывод:

    [Session started at 2009-09-11 16:16:12 -0700.]
    2009-09-11 16:16:14.527 TestApp[12800:207] @selector(doSomething)
    2009-09-11 16:16:14.531 TestApp[12800:207] @selector(doSomethingElse)
    

    Подробнее о sel_registerName () в Objective-C 2.0 Справочник по среде выполнения .

    4
    ответ дан 6 December 2019 в 06:50
    поделиться

    Похоже, вы заново изобретаете NSCell. Если вы хотите реализовать меню, почему бы не использовать существующие классы пользовательского интерфейса?

    -1
    ответ дан 6 December 2019 в 06:50
    поделиться