2010-07-14 3 views
8

J'essaie d'utiliser UIMenuController pour un menu dynamique (les titres et les actions proviennent d'un serveur). Le problème est que je dois utiliser UIMenuItems initWithTitle: action: où action est un @selector.UIMenuItems dynamiques avec @selector et méthodes dynamiques

Je peux utiliser @selector (dispatch :) mais je ne suis pas capable de distinguer lequel des éléments l'utilisateur a pressé. - (void) dispatch: (id) expéditeur {NSLog (@ "% @", expéditeur); } dit que c'est un UIMenuController et qu'il n'y a pas de méthode qui dirait quel élément de menu a été pressé.

Je ne peux pas écrire 100 méthodes pour envoyer tous les sélecteurs possibles, ok il n'y en aura pas plus de 10 mais encore, cela ne semble pas une bonne idée. Dois-je créer des méthodes dynamiques pour chaque sélecteur de ce type?

http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html? Cela semble étrange aussi.

De meilleures propositions alors ce deux?

// Cette approche ne fonctionne pas.

- (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 
} 

// Cette approche est vraiment moche.

- (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]; } 

Répondre

10

Cette approche fonctionnerait bien que vous ayez besoin d'un nom de sélecteur unique pour chaque bouton et d'un mappage de ce nom vers ce que vous voulez cibler.
Pour le nom du sélecteur, une chaîne unique doit être choisie (UUID ou peut-être une version & aseptisée du titre fonctionnerait). Ensuite, vous avez besoin d'une méthode qui résout l'appel et « alias » avec les différents noms de sélection:

- (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], "[email protected]:@"); 
     // now add menu item with sel as the action 
    } 
} 

Maintenant, le porteur peut regarder ce que l'URL est associée à l'élément de menu:

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

Pour générer les sélecteurs que vous pouvez utiliser quelque chose comme:

- (SEL)uniqueActionSelector { 
    NSString *unique = ...; // the unique part 
    NSString *selString = [NSString stringWithFormat:@"menu_%@:", unique]; 
    SEL sel = sel_registerName([selString UTF8String]); 
    return sel; 
} 
+0

D'où vient le _cmd et qu'est-ce que c'est? – Jeena

+2

@jen: un mot-clé pour le sélecteur avec lequel la fonction d'implémentation est appelée. Essayez de vous connecter 'NSStringFromSelector (_cmd)'. –

+1

Travail génial Guys, Merci beaucoup. – sachin

0

À moins que les éléments de menu font la même chose, pourquoi devraient ils partagent une action? Je voudrais aller de l'avant et écrire des actions qui spécifient un comportement que vous voulez et lier les éléments de menu jusqu'à ceux.

+1

Le problème est que je ne peux pas savoir quelles actions il y aura au moment de la compilation parce que les actions seront c Dans le cas d'un serveur, il s'agit toujours d'un titre pour le menu et d'un URL http qui doit être appelé lorsque l'utilisateur clique dessus. Je vais mettre à jour la question avec du code. – Jeena