2010-07-14 18 views
8

Sto cercando di utilizzare UIMenuController per un menu dinamico (titoli e azioni provengono da un server). Il problema è che devo usare UIMenuItems initWithTitle: action: dove action è un @selector.UIMenuItem dinamici con @selector e metodi dinamici

Posso usare @selector (invio :), ma non sono in grado di distinguere tra gli elementi che l'utente ha premuto. - (void) dispatch: (id) sender {NSLog (@ "% @", mittente); } dice che è un UIMenuController e non ha un metodo che indichi quale voce del menu è stata premuta.

Non posso scrivere solo 100 metodi per inviare tutti i possibili selettori, ok non ce ne saranno più di 10 ma ancora, questa non sembra una buona idea.

Devo creare metodi dinamici per ciascuno di questi selettori? http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html? Anche questo sembra strano.

Qualunque proposta migliore di questa?

// Questo approccio non funziona.

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

// Questo approccio è davvero brutto.

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

risposta

10

Questo approccio funzionerebbe, anche se è necessario un nome selettore univoco per ogni pulsante e una mappatura da quel nome a qualsiasi cosa si desideri targetizzare.
Per il nome del selettore deve essere scelta una stringa univoca (potrebbero funzionare UUID o una versione con prefisso & sterilizzata del titolo). Allora avete bisogno di un metodo che risolve la chiamata e "alias" con i diversi nomi di selezione:

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

Ora lo spedizioniere può cercare ciò URL associato alla voce di menu:

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

Per generare i selettori si potrebbe usare qualcosa di simile:

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

Da dove viene il _cmd e che cos'è? – Jeena

+2

@jen: una parola chiave per il selettore con cui viene richiamata la funzione di implementazione. Prova a registrare 'NSStringFromSelector (_cmd)'. –

+1

Fantastici ragazzi, Grazie mille. – sachin

0

A meno che le voci di menu fanno la stessa cosa, perché dovrebbero condividono un'azione? Vorrei andare avanti e scrivere azioni che specificano un comportamento che si desidera e collegare le voci di menu fino a quelle.

+1

Il problema è che non posso sapere quali azioni ci sarà al momento della compilazione perché le azioni saranno c da un server, è sempre un titolo per il menu e un url http che dovrebbe essere chiamato quando l'utente esegue il klicks su di esso. Aggiornerò la domanda con un po 'di codice – Jeena