I want a dynamically submenu. Now I tried this way:
#interface AppController()
#property(strong) Accounts * accView;
#property (weak) IBOutlet NSMenuItem *serverMenu;
#end
#implementation AppController
-(void)awakeFromNib {
_accView = [[Accounts alloc] initWithNibName:#"Accounts" bundle:nil];
[self.viewk addSubview:[_accView view]];
[[_accView view] setFrame:self.viewk.bounds];
NSMenuItem * testItem = [[NSMenuItem alloc] initWithTitle:#"Test" action:#selector(test:) keyEquivalent:#""];
[[_serverMenu submenu] addItem:testItem];
}
- (void)test:(id)test {
}
Then it get's added but I can't click on it. It's like this:
How can enable it?
You also need to assign a target to your NSMenuItem, like
[testItem setTarget:self];
Related
I have 2 methods that add the Previous, Next & Done toolbar above the iOS Keyboard and handle these actions. I'm looking for a way to code these methods once and reuse it across multiple UITableViewControllers. (DRY Code)
I find myself copy and pasting these methods into each UITableViewController. If I make a small change, I have to copy and pastes that change everywhere. The code below is just an example, I seem to be repeating myself a lot in my code.
Here's an example of the code I'd like to reuse:
- (void) createInputAccessoryView
{
_inputAccView = [[UIView alloc] initWithFrame:CGRectMake(10,0,310,42)];
UIToolbar *keyboardToolbar = [[UIToolbar alloc] init];
keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
[keyboardToolbar sizeToFit];
_segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Previous", #"Next", nil]];
[_segmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[_segmentedControl addTarget:self action:#selector(nextPrevious:) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *nextPrevButton = [[UIBarButtonItem alloc] initWithCustomView:_segmentedControl];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard)];
NSArray *barItems = [NSArray arrayWithObjects:nextPrevButton, flexSpace, doneBtn, nil];
[keyboardToolbar setItems:barItems];
[_inputAccView addSubview:keyboardToolbar];
}
- (void) nextPrevious:(id) sender
{
switch(_activeTxtField.tag) {
case 1:
//Recipe Name
if (_segmentedControl.selectedSegmentIndex == 1){
[_descriptionTextField becomeFirstResponder];
_activeTxtField = _descriptionTextField;
}
break;
case 2:
//Recipe Description
if (_segmentedControl.selectedSegmentIndex == 0){
[_nameTextField becomeFirstResponder];
_activeTxtField = _nameTextField;
}
default:
break;
}
}
Create a custom UIView that defines the common input accessory view. Should include a definition of a delegate to allow the class using the accessory view to handle, for example, previous/next button taps as appropriate. Here's a header file example for a keyboard accessory view:
#import <UIKit/UIKit.h>
#class KeyboardAccessoryView;
#protocol KeyboardAccessoryViewDelegate <NSObject>
-(void)accessoryNext:(id)sender;
-(void)accessoryPrevious:(id)sender;
#end
#interface InputAccessoryView : UIView
#property (nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate;
#property (nonatomic, setter = enablePrevious:) BOOL previousEnabled;
#property (nonatomic, setter = enableNext:) BOOL nextEnabled;
-(id)initPreviousNextAccessory;
#end
Edit - showing details of use in a UIViewController.
The .h file:
#import <UIKit/UIKit.h>
#import "KeyboardAccessoryView.h"
#interface MyViewController : UIViewController <KeyboardAccessoryViewDelegate>
//...
#end
The .m file:
#import "MyViewController.h"
#interface MyViewController () {
KeyboardAccessoryView *inputAccessoryView;
}
#end
#implementation MyViewController
//...
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputAccessoryView = [[KeyboardAccessoryView alloc] initPreviousNextAccessory];
inputAccessoryView.delegate = self;
//...
}
-(void)accessoryNext:(id)sender{
// handle Next
}
-(void)accessoryPrevious:(id)sender{
// handle Previous
}
//...
#end
I'm using .XIB and without ARC. I'm passing the value of the NSMultableArray to another view, if I put [self presentModel...], it works, but if I call the AnotherView with a button the value of the NSMultableArray of the AnotherView is null!
AnotherView.h
#interface AnotherViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>{
NSMutableArray *otherAnother;
NSMutableArray *arrayOfTheAnotherView;
}
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) NSMutableArray *arrayOfTheAnotherView;
AnotherView.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
otherAnother = [[NSMutableArray alloc]init];
otherAnother = [[NSMutableArray alloc]initWithArray:self.arrayOfTheAnotherView];
// [otherAnother addObjectsFromArray:arrayOfTheAnotherView];
NSLog(#"%#", self.arrayOfTheAnotherView);
}
The NSLog has written "null"
CurrentView.h
#interface CurrentViewController : UIViewController {
NSMutableArray * arrayCurrentView;
AnotherViewController *superAnotherView;
}
#property (retain, nonatomic) AnotherViewController *superAnotherView;
CurrentView.m
#synthesize superAnotherView;
NSString *x = [[NSString alloc]initWithFormat:#"%#",[label text]];
arrayCurrentView = [[NSMutableArray alloc]init];
[arrayCurrentView retain];
[arrayCurrentView addObject:x];
self.superAnotherView = [[AnotherViewController alloc]initWithNibName:nil bundle:nil];
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
[self.superAnotherView.arrayOfTheAnotherView addObjectsFromArray:arrayCurrentView];
I don't know how to retain the value of the NSMultableArray, thanks the help.
It is how I call the AnotherView:
UIButton *buttonAnother = [UIButton buttonWithType:UIButtonTypeCustom]; [buttonAnother setTag:5]; [buttonAnother addTarget:self action:#selector(switchTabBar:) forControlEvents:UIControlEventTouchDown];
[tabBarViewController.view addSubview:buttonAnother];
- (IBAction)switchTabBar:(id)sender { switch ([(UIButton *)sender tag]) { case 5: [self.tabBarController setSelectedIndex:0]; break; }
These should not be necessary:
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
Properties are already initialized when the class is initialized.
In fact, your explicit retain lines shouldn't be necessary at all; you're not releasing them as far as I can see and just making the retain count 2 so that it has to be released twice.
I think there's something going on here that the methods and view controllers are not being called in the order you want, probably something to do with the tab bar.
I dicoverd! I'm using the MVC
A array of the APP delegate don't lost its value.
AppDelegate
NSMutableArray *arrayDelegate;
View.m
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate.arrayDelegatePedido addObject:#"title"]; //for example
I have created an NSSearchField that stores a list of recent searches. The search field is connected to a method that updates a label in the window with the text typed into the search field. The problem is that the label updates as soon as the user types into the search field, I need the label to not update until after the user types the text then hits the Enter key. I can do this with the typical NSTextField but I want to use the NSSearchField so I can show recent searches. Please see my code below and offer some suggestions. Thanks.
Interface file:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSSearchField *searchField;
#property (weak) IBOutlet NSTextField *textField;
- (IBAction)searchString:(id)sender;
#end
Implementation file:
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize searchField, textField;
- (void)awakeFromNib {
if ( [searchField respondsToSelector:#selector(setRecentSearches:)] ) {
NSMenu *searchMenu = [[NSMenu alloc] initWithTitle:#"Search Menu"];
[searchMenu setAutoenablesItems:YES];
NSMenuItem *recentsTitleItem = [[NSMenuItem alloc] initWithTitle:#"Recent Searches" action:nil keyEquivalent:#""];
[recentsTitleItem setTag:NSSearchFieldRecentsTitleMenuItemTag];
[searchMenu insertItem:recentsTitleItem atIndex:0];
NSMenuItem *norecentsTitleItem = [[NSMenuItem alloc] initWithTitle:#"No recent searches" action:nil keyEquivalent:#""];
[norecentsTitleItem setTag:NSSearchFieldNoRecentsMenuItemTag];
[searchMenu insertItem:norecentsTitleItem atIndex:1];
NSMenuItem *recentsItem = [[NSMenuItem alloc] initWithTitle:#"Recents" action:nil keyEquivalent:#""];
[recentsItem setTag:NSSearchFieldRecentsMenuItemTag];
[searchMenu insertItem:recentsItem atIndex:2];
NSMenuItem *separatorItem = (NSMenuItem*)[NSMenuItem separatorItem];
[separatorItem setTag:NSSearchFieldRecentsTitleMenuItemTag];
[searchMenu insertItem:separatorItem atIndex:3];
NSMenuItem *clearItem = [[NSMenuItem alloc] initWithTitle:#"Clear" action:nil keyEquivalent:#""];
[clearItem setTag:NSSearchFieldClearRecentsMenuItemTag];
[searchMenu insertItem:clearItem atIndex:4];
id searchCell = [searchField cell];
[searchCell setMaximumRecents:20];
[searchCell setSearchMenuTemplate:searchMenu];
}
}
- (IBAction)searchString:(id)sender {
[textField setStringValue:[searchField stringValue]];
}
#end
If you don't want to do it in code, view your nib file, select the search field and choose "Sends whole search string"
Like So:
Hope this helps!
You need to use [searchField.cell setSendsWholeSearchString:YES]
I have a NSMenuItem with a custom view. However, when I want to update the first row in the menu it add the content as it is in the xib file, not as I set it.
My code:
AppDelegate.m:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_helper = [[Helper alloc] init];
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[statusItem setMenu:self.statusMenu];
[statusItem setTitle:#"GravAccount"];
[statusItem setHighlightMode:YES];
_gravatarLoader = [[GravatarLoader alloc] initWithTarget:self andHandle:#selector(setGravatarImage:)];
// Get email address
_email = [_helper getEmailAddress];
if (_email != nil)
{
[_gravatarLoader loadEmail:_email withSize:50.0];
}
}
- (void)setGravatarImage:(NSImage*)image
{
NSLog(#"Image loaded!");
GravatarMenuItem *menuItem = [[GravatarMenuItem alloc] initWithNibName:#"GravatarMenuItem" bundle:nil];
[menuItem.label setTitle:_email];
[menuItem.imageView setImage:image];
NSLog(#"Email: %#", _email);
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
[item setView:menuItem.view];
[self.statusMenu removeItemAtIndex:0];
[self.statusMenu insertItem:item atIndex:0];
}
GravatarMenuItem.h:
#import <Cocoa/Cocoa.h>
#interface GravatarMenuItem : NSViewController
#property (nonatomic, strong) IBOutlet NSImageView *imageView;
#property (nonatomic, strong) IBOutlet NSTextFieldCell *label;
#end
The outlets are linked in the XIB file on the file's owner.
This is the result:
Log:
2012-03-09 16:57:24.314 appName[51158:403] Image loaded!
2012-03-09 16:57:24.316 appName[51158:403] Email: Paul#******.se
Result:
When you do:
GravatarMenuItem *menuItem = [[GravatarMenuItem alloc] initWithNibName:#"GravatarMenuItem" bundle:nil];
It only creates the view controller. It doesn't actually load the view from the nib. When you access the properties, they are most likely nil as the view has not been loaded (and the connections have not been made).
If you update your code to the following, everything should work fine:
GravatarMenuItem *menuItem = [[GravatarMenuItem alloc] initWithNibName:#"GravatarMenuItem" bundle:nil];
[menuItem view]; // load the view from the nib
[menuItem.label setTitle:_email];
[menuItem.imageView setImage:image];
in my .h I have
IBOutlet NSMutableArray *buttons;
#property (nonatomic, retain) IBOutletCollection(UIButton) NSMutableArray *buttons;
-(void)play:(UIButton *)theButton;
in my .m I have
-(void)initButtons{
buttons = [[NSMutableArray alloc] initWithCapacity:1];
UIButton *myBut = [UIButton alloc];
[buttons addObject: myBut];
[[buttons objectAtIndex:0] addtarget:self action#selector(play:) forControlEventTouchUpInside];
}
...
-(void)dealloc{
[buttons dealloc];
[super deallloc];
}
.....
-(void)viewDidLoad{
[super viewDidLoad];
[self initButtons];
}
I dragged the buttons IBoutletCollection in interface builder to a simple button, but when I test it it doesn't perform the expected action;
I should mention that if I turn my action into (IBAction) instead of (void) and link it to the button it works;
I don't understand very well NSArrays and outlet collections.
The array is set for you with whatever buttons you've connected to the collection in the NIB. It fails to do anything because you've reset the ivar here:
buttons = [[NSMutableArray alloc] initWithCapacity:1];
…or because you've not connected buttons to the collection.
You don't need outlets to connect buttons to methods.
Get rid of all your outlet and property and initButtons code and just have this:
//in .h
-(IBAction)play:(UIButton *)theButton;
//in .m
-(IBAction)play:(UIButton *)theButton
{
//the code for your play action
}
Then in Interface Builder, ctrl-drag from the button to the File's Owner and select the play: action.
Declare your UIButton myBut as an IBOutlet with property in .h file.connect your button outlet in xib to myBut.No need to declare NSMutableArray as an IBOutletCollection or IBOutlet.You simply declare it and No need to allocate myBut again inside initButtons method.
You can do like this.
viewController.h
#property (strong, nonatomic) IBOutlet UIButton *myButton;
#property (nonatomic,strong) NSMutableArray *buttons;
-(void)initButtons;
-(void)play:(id)sender;
inSide xib connect your button outlet to myButton
viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self initButtons];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)initButtons{
buttons = [[NSMutableArray alloc] initWithCapacity:1];
[buttons addObject: myButton];
[[buttons objectAtIndex:0] addTarget:self action:#selector(play:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)play:(id)sender
{
NSLog(#"button tapped");
}