How do you send a message to a button from different views? - objective-c

I have an app that has a main view that acts as a view controller. This main view has 3 buttons on it. I have 3 subviews that I swap in and out of this main view, controlled by the 3 buttons. Each of the subviews has a button on it. When this button is pressed I want it to disable the 3 buttons on the main view until the button is pressed again. Is there a way to send a message between the views to disable the buttons?

This sounds like a toggle to me. More like a setting. If you think about it, this should go in NSUserDefaults. And when you that particular view is coming on, probably in viewWillAppear: or viewDidAppear:, do this,
BOOL controlsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"ControlsEnabledKey"];
button1.enabled = controlsEnabled;
button2.enabled = controlsEnabled;
button3.enabled = controlsEnabled;
To save the value on that button press,
BOOL controlsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"ControlsEnabledKey"];
[[NSUserDefaults standardUserDefaults] setBool:!controlsEnabled forKey:#"ControlsEnabledKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
note Since the boolForKey: will return NO if the key is not found, I suggest you set the value to YES when the application starts if you want the controls to be enabled at launch.

Use NSNotifications to post a notification that the buttons were pressed.
[[NSNotificationCenter defaultCenter] postNotificationName:#"Button1Pressed" object:self userInfo:info];
And then add observers such that they listen to these notifications.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(buttonPress:) name:#"Button1Pressed" object:nil];
Now implement buttonPress
Read HERE for the NSNotification manual and learn to use it .

Set the main view/controller as the delegate of the inner views, define a protocol in which you define a method, say, toggleMainButtons, have the VC conform to that protocol and implement the message. On the buttons, addTarget:self.delegate action:#selector(toggleMainButtons) forControlEvents:UIControlEventTouchUpInside.

Related

Objective-C: Pass data between two not connected View Controllers

I have a ViewController A with a UILabel and a ViewController B with a button, so I want to update the label once I press the button. I could use delegates for this, but my ViewControllers are not connected and I can't use something like setDelegate, I don't create any instance of one in another. So basically they are created somewhere else. Is there any way to do that?
Variant 1: if ControllerA and ControllerB life-time differs
Use NSUserDefaults. On ControllerB button click store data into NSUserDefaults, in ControllerA read data from NSUserDefaults and show in label (NSUserDefaults is also observable, so can track changes in run-time)
Variant 2: if ControllerA and ControllerB both currently in run-time
Use NSNotificationCenter. On ControllerB button click post a NSNotification with data in userInfo, and ControllerA in notification handler extracts data from userInfo and assign to label.
Use Coordinator pattern.
Class that will create/get the 2 instances of both VCs,
and with delegates will move the data between them.
The advantage of Coordinator pattern is that your VCs can be re-used on others places (same or other project), and also the code is cleaner.
To expand on Apsperi's answer:
Notification method of changing the view controller:
In the view controller with the button on button press call:
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh"
object:self userInfo:nil];
Then in the viewdidload or viewdidappear method of the label view controller place the "receiver" for the notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mymethotochangetext) name:#"refresh" object:nil];
The NSUserDefault method:
In the view controller with the button save a NSUserDefualt:
[[NSUserDefaults standardUserDefaults] setObject:somestring
forKey:#"myuniquekeyname"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then in the view controller with the label you can get the saved string when the view loads and place it in the text field:
self.label.text=[[NSUserDefaults standardUserDefaults]
stringForKey:#"myuniquekeyname"];

How can I be notified when a control becomes key? I want t o have my custom warning popover NSWindow autohide and show; only the hide part works

I have a custom NSWindow subclass that's used to display a pop-out warning on NSTextFields. I want the warning to automatically hide when the NSTextField loses key status, and to show again when it gains key. So I have
self.onBegin = [[NSNotificationCenter defaultCenter] addObserverForName:NSControlTextDidBeginEditingNotification
object:self.textfield
queue:nil
usingBlock:^(NSNotification *note){
[self orderFront:self];
}];
self.onEnd = [[NSNotificationCenter defaultCenter] addObserverForName:NSControlTextDidEndEditingNotification
object:self.textfield
queue:nil
usingBlock:^(NSNotification *note){
[self orderOut:self];
}];
onEnd works fine: the custom window hides itself when I tab away from the text field or do something else, etc. But onBegin doesn't seem to fire until I start actually changing the contents of the text field.
Is there some other option I can use? Should I not be using notifications for this, or is there some API (must be 10.7+) that I don't know about? Thanks.
You can use Key-Value Observing (KVO) to monitor the firstResponder property of the window containing the text fields. When you get notified that the first responder has changed, you can check if it's one of the text fields you're interested in. Note, though, that the window's firstResponder won't be the text field itself, it will be the text view that serves as the field editor for the text field. To determine which text field the field editor serves, you check the field editor's delegate.
See Cocoa Event Handling Guide: Event Handling Basics – Determining First-Responder Status.
if ([window.firstResponder isKindOfClass:[NSTextView class]] &&
[window fieldEditor:NO forObject:nil] != nil)
{
NSTextField *field = [window.firstResponder delegate];
// Do something with 'field', which is the text field that has focus
}

How can I save a boolean value to hide or show a button?

My Question concerns an easy way for a game level selection.
For example: I have two ViewControllers. On one ViewController I programmed a game code. If I achieve the game goal I will show a hidden button (UIButton.hidden = NO) which links me to the other ViewController with the next level. So far so good.
But I would love to save this state, so when I close and open the app again, this hidden button should still be available because I already achieved the goal of this level.
I tried using NSUserDefaults, but I couldn't figure out how to save a boolean. How can I save an if/else state for button trigger?
Not sure if I'm missing something, but it sounds fairly straightforward:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"buttonVisible"];
BOOL buttonVisible = [[NSUserDefaults standardUserDefaults] boolForKey:#"buttonVisible"];
Concerning the below discussion. The notification pattern would look something like this:
In the viewController where the necessary goal is achieved:
[[NSNotificationCenter defaultCenter] postNotificationName:#"nextLevelGoalAchieved" object:nil];
In the viewController where you need to be made aware of the change:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(makeLevelButtonVisible) name:#"nextLevelGoalAchieved" object:nil];

Reloading NSTableView on re-focus

In my application, I have a NSWindow that has a NSTableView object and a few buttons. When the user presses the "new" button, an "ItemAdd" NSWindowController is activated where the user types in attributes for the item to be added to the NSTableView.
My question is this: since NSTableView requires reloadDatato update its view, how do I call reloadData after the ItemAdd window closes and focus shifts back to the NSWindow with the NSTableView.
Thanks for the help!
You could put reload data in a notification handler:
Put this in an initialization method of an object that you want the notification to get called on:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didBecomeMainWindow) name:#"NSWindowDidBecomeKeyNotification" object:nil];
Then make a method something like this:
- (void) didBecomeMainWindow
{
[tableView reloadData];
}
You can subclass the NSWindow and override the following method:
- (void)becomeKeyWindow

Refresh NSView content when the view is displayed with MAAttachedWindow

Im my application, I display a NSView when a user click on an icon in the systemstatusbar.
This NSView is displayed with MAAttachedWindow.
My question is : how to refresh the NSView content when the attachedWindow is displayed (makeKeyandorderFront)
I've tried to refresh the content in the awakeFromNib method,but it works only once.
Could anyone help me?
thanks
The solution I've found:
I've added a observer in my view:
I've set the object to [selft window] to listen the NSWindowDidBecomeKeyNotification notification of the MAAttachedwindow.
-(void)awakeFromNib
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:[self window]];
}
-(void) windowDidBecomeKey:(NSNotification *)note
{
// Do refresh here
}
The reason -awakeFromNib only works once is presumably because you're only loading the assembly from the xib once and keeping it around.
Presumably whatever action actually shows your view in the MAAttachedWindow instance is the ideal place to "refresh" it before display, ie your own call to -makeKeyAndOrderFront:.
So: What have you tried?