带有@selector和动态方法的动态UIMenuItems [英] Dynamic UIMenuItems with @selector and dynamic methods
问题描述
我正在尝试使用UIMenuController进行动态菜单(标题和操作来自服务器)。问题是我必须使用UIMenuItems initWithTitle:action:where action是@selector。
I am trying to use UIMenuController for a dynamical menu (titles and actions come from a server). The problem is that I have to use UIMenuItems initWithTitle:action: where action is a @selector.
我可以使用@selector(dispatch :)但是我不能区分用户按下的项目。 - (void)dispatch:(id)sender {NSLog(@%@,sender);说它是一个UIMenuController,它没有一个方法可以告诉哪个菜单项被按下了。
I can use @selector(dispatch:) but then I am not able to distinguish which of the items the user pressed. - (void)dispatch:(id)sender { NSLog(@"%@", sender); } says it is a UIMenuController and It don't have a method which would tell which menu item was pressed.
我不能只写100个方法来调度每个可能的选择器,确定不会有超过10但仍然,这似乎不是一个好主意。
I can't just write 100 methods to dispatch every possible selector, ok there will not be more then 10 but still, this seems not a good idea.
我是否必须为每个这样的选择器创建动态方法? http://developer.apple.com/mac /library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html 的?这看起来也很奇怪。
Do I have to create dynamic methods for each such selector? http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html? This seems odd too.
那么这两个更好的命题呢?
Any better propositions then this two?
//这种方法不起作用。
// This approach doesn't work.
- (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
}
//这种做法非常难看。
// This approach is really ugly.
- (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]; }
推荐答案
这种方法可行,尽管你需要一个独特的方法每个按钮的selector-name以及从该名称到任何你想要定位的映射。
对于选择器名称,必须选择一个唯一的字符串(UUID或者可能是标题的已清理和前缀版本)会工作)。然后你需要一个解析调用的方法和alias它使用不同的选择器名称:
That approach would work, although you need a unique selector-name for every button and a mapping from that name to whatever you want to target.
For the selector name a unique string has to be chosen (UUIDs or maybe a sanitized & prefixed version of the title would work). Then you need one method that resolves the call and "alias" it with the different selector names:
- (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:
Now the forwarder can look up what URL is associated with the menu item:
- (void)forwarder:(UIMenuController *)mc {
NSLog(@"URL for item is: %@", [actionDict objectForKey:_cmd]);
}
要生成选择器,您可以使用以下内容:
To generate the selectors you could use something like:
- (SEL)uniqueActionSelector {
NSString *unique = ...; // the unique part
NSString *selString = [NSString stringWithFormat:@"menu_%@:", unique];
SEL sel = sel_registerName([selString UTF8String]);
return sel;
}
这篇关于带有@selector和动态方法的动态UIMenuItems的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!