Динамические UIMenuItems с @selector и динамическими методами - PullRequest
9 голосов
/ 14 июля 2010

Я пытаюсь использовать UIMenuController для динамического меню (заголовки и действия поступают с сервера). Проблема в том, что мне нужно использовать UIMenuItems initWithTitle: action: где action - это @ селектор.

Я могу использовать @selector (dispatch :), но тогда я не смогу различить, какие пункты нажал пользователь. - (недействительная) отправка: (id) отправитель {NSLog (@ "% @", отправитель); } говорит, что это UIMenuController и у него нет метода, который бы указывал, какой пункт меню был нажат.

Я не могу просто написать 100 методов для отправки каждого возможного селектора, хорошо, не будет больше 10, но все же, это не очень хорошая идея.

Нужно ли создавать динамические методы для каждого такого селектора? http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html? Это тоже странно.

Есть ли лучшие предложения, чем эти два?

// Этот подход не работает.

- (void)showMenu {

    [self becomeFirstResponder];

    NSMutableArray *menuItems = [[NSMutableArray alloc] init];

    UIMenuItem *item;
    for (MLAction *action in self.dataSource.actions) {
        item = [[UIMenuItem alloc] initWithTitle:action.title action:@selector(action:)];
        [menuItems addObject:item];
        [item release];
    }

    UIMenuController *menuController = [UIMenuController sharedMenuController];
    menuController.menuItems = menuItems;
    [menuItems release];
    [menuController update];
    [menuController setMenuVisible:YES animated:YES];

}

- (void)action:(id)sender {
    NSLog(@"%@", sender); // gives UIMenuController instead of UIMenuItem
    // I can not know which menu item was pressed
}

// Этот подход действительно безобразен.

- (void)showMenu {

    [self becomeFirstResponder];

    NSMutableArray *menuItems = [[NSMutableArray alloc] initWithCapacity:5];

    UIMenuItem *item;
    NSInteger i = 0;
    for (MLAction *action in self.dataSource.actions) {
        item = [[UIMenuItem alloc] initWithTitle:action.text
                                                                            action:NSSelectorFromString([NSString stringWithFormat:@"action%i:", i++])];
        [menuItems addObject:item];
        [item release];
    }

    UIMenuController *menuController = [UIMenuController sharedMenuController];
    menuController.menuItems = menuItems;
    [menuItems release];
    [menuController update];
    [menuController setMenuVisible:YES animated:YES];

}

- (void)action:(NSInteger)number {
    NSLog(@"%i", number); // gives the index of the action in the menu.
}

// This is a hack, I have to assume that there will never be more then 15 actions
- (void)action0:(id)sender { [self action:0]; }
- (void)action1:(id)sender { [self action:1]; }
- (void)action2:(id)sender { [self action:2]; }
- (void)action3:(id)sender { [self action:3]; }
- (void)action4:(id)sender { [self action:4]; }
- (void)action5:(id)sender { [self action:5]; }
- (void)action6:(id)sender { [self action:6]; }
- (void)action7:(id)sender { [self action:7]; }
- (void)action8:(id)sender { [self action:8]; }
- (void)action9:(id)sender { [self action:8]; }
- (void)action10:(id)sender { [self action:10]; }
- (void)action11:(id)sender { [self action:11]; }
- (void)action12:(id)sender { [self action:12]; }
- (void)action13:(id)sender { [self action:13]; }
- (void)action14:(id)sender { [self action:14]; }

Ответы [ 2 ]

11 голосов
/ 15 июля 2010

Этот подход будет работать, хотя вам нужно уникальное имя селектора для каждой кнопки и сопоставление этого имени с тем, на что вы хотите нацелиться.
Для имени селектора должна быть выбрана уникальная строка (UUID или, возможно,будет работать исправленная и префиксированная версия заголовка).Затем вам нужен один метод, который разрешает вызов и "псевдоним" с разными именами селектора:

- (void)updateMenu:(NSArray *)menuEntries {
    Class cls = [self class];
    SEL fwd = @selector(forwarder:);
    for (MenuEntry *entry in menuEntries) {
        SEL sel = [self uniqueActionSelector];
        // assuming keys not being retained, otherwise use NSValue:
        [self.actionDict addObject:entry.url forKey:sel]; 
        class_addMethod(cls, sel, [cls instanceMethodForSelector:fwd], "v@:@");
        // now add menu item with sel as the action
    }
}

Теперь сервер пересылки может посмотреть, какой URL связан с элементом меню:

- (void)forwarder:(UIMenuController *)mc {
    NSLog(@"URL for item is: %@", [actionDict objectForKey:_cmd]);
}

Для генерации селекторов вы можете использовать что-то вроде:

- (SEL)uniqueActionSelector {
    NSString *unique = ...; // the unique part
    NSString *selString = [NSString stringWithFormat:@"menu_%@:", unique];
    SEL sel = sel_registerName([selString UTF8String]);
    return sel;
}
0 голосов
/ 15 июля 2010

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

...