I am building an interface, where I can add events like in a calendar.
In the AddAEventViewController I have Buttons to set the starttime, duration and recurrence.
Every time you press a button a viewcontroller comes up with a UIDatePicker, where you can set your time. The picked component is than displayed in a UITextField. Now when I press the Done-Button, it dismisses the ModalViewController and I am back to my AddAEventViewController. Next to the Durationbutton e.g. is a UILabel, where I want to show now the just picked and in the textfield shown duration.
How do I get access to the AddEventViewController out of an other ViewController? I tried to alloc and init a new one there, but it didnt work!
- (IBAction)pressedDoneButton:(id)sender {
_mainAddWishViewController.labelDuration.text=textFieldDuration.text;
[self dismissModalViewControllerAnimated:YES];
}
Can someone help me please!
Thank you Jules
There are several ways you can do this, all of them documented here. Reading and understanding them will help you a lot in iOS software development.
There are many ways to achieve this. Here is one that is fairly straightforward.
In the "child" viewController, add a delegate property and set it to the parent view controller.
Then in your Done button handler, do something like:
[self.delegate performSelector:#selector(didComplete) withObject:self]
In the parent view controller, define a method as follows:
- (void) didComplete: (YourSubViewControllerClass *) sender
{
self.labelDuration.text = sender.textFieldDuration.text
}
Basically, this implements an informal protocol whereby the subViewController informs the main view controller that it is finished and input values are available.
Note that if you cancel out of the subViewController, don't send the didComplete message.
Related
can anyone say how do i observe for action in Reactive Cocoa for a UIButton or UIControl..
An alternative way is to bind the view to the view model.And observe changes on the Mutable Property.
I tried using below code but none is firing.
self.rollBtn.reactive.trigger(for: .touchUpInside).observeValues {
value in
print(value)
}
EDIT: Actually i am trying to get the sender on button Tap..how can i do that?
You have done nothing wrong in this code snippet - trigger(for:) is one of the ways to get notified in RAC 5.0. It should print () for every press on the button.
Have you linked the button with the view, if you are using Storyboard or Interface Builder? Where did you place this piece of code? Make sure you place it in viewDidLoad or awakeFromNib so that it gets called before the view is presented.
-
EDIT: Actually i am trying to get the sender on button Tap..how can i do that?
As mentioned in the comments, trigger(for:) returns a Signal<(), NoError>. It doesn't include the sender with the value event. You would need to reference the sender manually, e.g.:
button.reactive
.trigger(for: .touchUpInside)
.observeValues { [unowned button] in
_ = button
}
I'm trying to change the title of a button after I call back from a notification but it doesn't respond at all. I checked it's not nil and checked the text Im' assigning and all is good. I made the property type strong instead of weak but no success.
- (void) setButtonTitleFromSelectedSearchResult:(NSNotification *)notif
{
[self popController];
self.sourceMapItem = [[notif userInfo] valueForKey:#"SelectedResult"];
NSLog(#"The Selected Result is: %#", self.sourceMapItem.name);
//Testing
NSLog(#"%#", self.fromButton); // check it's not nil
[self.fromButton setTitle:self.sourceMapItem.name];
}
With WatchKit, if a user interface element isn't currently visible, it cannot be updated. So, if you've presented another interface controller "on top", you can't update any of the presenting controller's interface elements until you've dismissed the presented controller. At that point, you can safely update the presenting controller in its willActivate method.
SushiGrass' method of passing blocks is certainly one valid approach. In my testing, however, I ended up having to manage multiple blocks, and many of the subsequent blocks reversed what earlier queued blocks had accomplished (for example, first changing a label's text to "foo", then "bar", then "foo" again. While this can work, it isn't optimal.
I'd suggest that anyone who is working on a WatchKit app takes a moment to consider how they want to account for off-screen (i.e. not-currently-visible) interface elements. willActivate is your friend, and coming up with a way to manage updates in that method is worthwhile if you're moving from controller to controller.
For what it's worth, I've encapsulated a lot of this logic in a JBInterfaceController subclass that handles a lot of this for you. By using this as a base class for your own interface controller, you can simply update your elements in the added didUpdateInterface method. Unfortunately, I haven't yet had the time to write proper documentation, but the header files and sample project should get you going: https://github.com/mikeswanson/JBInterfaceController
I'm using latest XCode 6.3 and below code working with me.
self.testBtn is bind with Storyboard and its WKInterfaceButton
I also have attached screenshot with affected result.
I'm setting initial text in - (void)willActivate
- (void)willActivate {
[super willActivate];
[self.testBtn setTitle:#"Test"];
[self performSelector:#selector(justDelayed) withObject:nil afterDelay:5.0]
}
-(void)justDelayed
{
[self.testBtn setTitle:#"Testing completed...!!"];
}
If you're using an IBOutlet for the property fromButton be sure that is connected to WKInteface on the storyboard, like below:
I solved this kind of issue by creating a model object that has a property that is a block of type () -> (Void) (in swift). I create the model object, set the action in the block that I'd like the pushing WKInterfaceController to do on completion, and finally pass that model object in the context to the pushed WKInterfaceController. The pushed WKInterfaceController holds a reference to the model object as a property and calls it's completion block when it's done with whatever it needs to do and after func popController().
This worked for me for patterns like what you are describing along with removing rows on detail controller deletion, network calls, location fetches and other tasks.
You can see what I'm talking about here: https://gist.github.com/jacobvanorder/9bf5ada8a7ce93317170
I am designing apple watch application where i need to show top10 feed title and i have successfully shown it. in next step i have to add action event to tap which will redirect user to next screen but i am confused which controller to use here. i have to show all feeds in pagination format and then on click i have to show its detail view.
does anyone tried with this approach? i am using UIButton over there but its having text limitation so cant use it and for tableview it scroll verticaly where as i need horizantle scroll.
alph0x's answer is pretty useful. But you can also do another thing to perform what you are asking in case you only want that the action will do when push in a specific button of the row.
This second solution consists on create a class for the custom row with an IBAction
#import <WatchKit/WatchKit.h>
#interface MyRow : NSObject
// Methods
- (IBAction)buttonClick;
#end
And in the buttonClick method, you can specify the action as in the follow example using pushControllerWithName:context to go to a specific interface controller
#import "MyRow.h"
#implementation MyRow
- (IBAction)buttonClick {
[self goToInterface:#"feedInterface"];
}
- (void)goToInterface:(NSString *)interfaceName{
NSDictionary *contextToSend = [NSDictionary dictionaryWithObjectsAndKeys:#"FeedTitle", #"title",
#"lalala", #"secondValue",
#"lelele", #"thirdValue",
#"other value", #"other", nil];
[self pushControllerWithName:interfaceName context:contextToSend];
}
#end
You can send your row info through context. In that example I have decided to send a dictionary with some values.
In the interfaceName param you have to specify the Interface Controller Identifier that you can set in your storyboard. See the image below:
And tell to the XCode that your table row has the custom class MyRow
Note: don't forget to assign your button to the IBAction method ;)
If I understand, you need to have a table with 10 rows, and you need to be able to tap in one row, and view the details about the one you selected, if thats correct, you only need to use the Method from WKInterfaceTable "- (id)rowControllerAtIndex:(NSInteger)index", with this one (works like UITableView one with the delegate) you can handle every row action after being tapped.
I have created a custom class for my UIBarButtonItem (refreshIndicator.m). This button will be on many different view controllers, all push-segued from my MainViewController/NavigationController.
Instead of dragging an outlet onto every single ViewController.m file for iPhone storyboard THEN iPad storyboard (ugh, still targeting iOS7), I want to know if there is a way to complete my task simply within my UIBarButtonItem custom class. I've looked around everywhere but I haven't quite found an answer to this,
All I need to do is check which UIViewController is present, check the last time the page was refreshed, and then based on that time, set an image for the UIBarButtonItem. (I've got this part figured out though, unless someone has a better suggestion). How can I check for the current UIViewController within a custom button class? Is this possible?
Does it need to know which view controller its on so it can tell that vc it was pressed? If that's the case, then use your button's inherited target and action properties. On every vc that contains an instance of the button, in view did load:
self.myRefreshIndicator.target = self;
self.myRefreshIndicator.action = #selector(myRefreshIndicatorTapped:);
- (void)myRefreshIndicatorTapped:(id)sender {
// do whatever
}
More generally, its better to have knowledge about the model flow to the views from the vc, and knowledge of user actions flow from the views. Under that principal, your custom button could have a method like:
- (void)timeIntervalSinceLastRefresh:(NSTimeInterval)seconds {
// change how I look based on how many seconds are passed
}
And your vcs:
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:self.lastRefreshDate];
[self.myRefreshIndicator timeIntervalSinceLastRefresh:interval];
If you really must go from a subview to a view controller, you could follow the responder chain as suggested in a few of the answers here (but I would go to great lengths to avoid this sort of thing).
It is possible to achieve this, but the solution is everything but elegant. It is one way of getting around the basic principles of iOS and is strongly discouraged.
One of the ways is to walk through the responder chain, posted by Phil M.
Another way is to look through all subviews of view controllers until you find the button.
Both ways are considered a bad practice and should be avoided.
For your particular case, I would rethink the structure of having a separate instance of the bar button. For example, you could rework it into a single UIButton instance that gets displayed over every view controller and it can also act as a singleton.
What's the difference between declaring a UIButton in Xcode like this:
- (IBAction)testButton;
and declaring a button like this:
- (IBAction)testButton:(id)sender;
I understand that in the .m file you would then implement the buttons accordingly, as shown below:
- (IBAction)testButton
{
// insert code here..
}
and setting it up like this:
- (IBAction)testButton:(id)sender
{
// insert code here..
}
Is there any additional things you can do by declaring the button with :(id)sender, is there some additional stability, or is there no difference?
With :(id)sender you are able to access the button itself through the sender variable. This is handy in many situations. For example, you can have many buttons and give each a tag. Then use the [sender tag] method to find which button was tapped if many buttons are using this IBAction.
- (IBAction)someMethod:(id)sender {
// do stuff
}
Using (id)sender, you have a reference to who sent the method call. Please note, this doesn't have to be limited to a UIButton.
If you're created this method via control-dragging from the storyboard an only hooking up a single button, then sender is basically useless (it will always be the same), and should probably be marked as unused:
#pragma unused (sender)
(The compiler can better optimize your code if you do this.)
However, there's nothing wrong with hooking up several UI elements to the same IBAction method. You can then distinguish the sender via:
[sender tag]
...which returns an int that was either set via the storyboard or programmatically.
Moreover, you can call this method elsewhere in your class. You can either pass nil as the sender, or you can pass it a particular UI element in order to force it into the results you've coded for objects of that tag.
Nonetheless, if you plan to call the method with a nil argument, you can always throw:
if(!sender)
... into the method in order to handle special logic for when the method has been invoked programmatically as opposed to via user interaction.
It allows you to know which button you are working with. I have posted a simple example for a card game below
- (IBAction)flipCard:(id)sender {
[self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender]];
self.flipCount++;
[self updateUI];
}
This method is used for a card flipping game. There are multiple buttons on the screen representing different cards. When you hit the button, a card in the model must be flipped. We know which one by finding the index of the variable sender