I have a main ViewController that eventually creates and presents a new ViewController, which is used to gather some user data. When the data is picked, I dismiss the second ViewController and use the completion field of the func "dismissViewControllerAnimated" to call a method from a delegate that lets me hand in the data to the first and main ViewController (it is important to say that this method, actually sends an instance of a class with the data, created and initialized just before calling "dismissViewControllerAnimated").
At the first and main ViewController, I have defined the delegate method to do the following:
· print the data fields of the received instance, to make sure I have my data on the ViewController I want.
· Call a method from the received instance's class, that creates and initializes a UIlabel with the data just printed in the previos step (this label is stored into one of this ViewController properties).
· self.view.addSubview(/* property of UILabel type, now filled with my own UILabel */)
Everything compiles and goes perfect till the addSubview part... I also print the property once is filled, to make sure it receives the correct data, and it does. But no UILabel appears on my first ViewController View. Also, I have made many tests through other methods, and after dismissing the second ViewController, no UIView of any kind is successfully displayed on the screen.
I have also tried to use self.view.reloadInputView() after addSubview, but although it compiles, it has no effect.
Could anyone offer me a clue or something that helps me know how are UIViews displayed after dismissing another ViewController? My code is written in swift.
Related
I have created all my views programatically and to the UIView I have created an extension. This extension is present in a different file called App+Extensions.swift
extension UIView {
func setupParentView() -> UIView {
//...
}
}
The setupParentView() gives me a view with my navbar and background colour. As the design is same everywhere I have used this function. This function is called everywhere in viewDidLoad. So, now in this function the navabar consists of points which need to updated every time the user has purchased/spent it.
So, now as this method is only called in viewDidLoad the function is not called again and the point value do not change in the navigation bar. So, how can I update the point value every time it is changed? I thought of using Combine, but this app will be available for iOS 12 users as well, and I am not using RxSwift, so any help?
Well ViewDidLoad won't get refreshed because your view is now in the stack hierarchy. Some override methods that do get called which have a relation to the view are viewWillAppear, viewDidDissapear, and viewDidAppear.
If your view is going back in forth and the point button needs to be updated everytime your view re-appears consider putting the "refresh" point number in one of the above methods.
Note if your sending info back and forth between two views its also best maybe implement a delegation pattern or an observer.
Use notifications.
In other words, have points be a property of a global object that lives off in "data space" as a singleton. Now just use a property observer so that whenever anyone changes that object's points property, it emits a notification through the NotificationCenter.
That way, any view or view controller that needs to update whenever the points property changes just has to register for that notification when it comes into existence.
[Basically, this is the mechanism, or one of the mechanisms, that you would be replacing or even using directly if you were using Combine or RxSwift.]
Create a custom view called NavBarView
This NavBarView has a property called point
var point = 0 { didSet { updateView() } }
You want to avoid singleton, single view object, so that not everything is coupled together.
You don't need RxSwift or notification to do this.
i initialize tables, data etc in my main ViewController. For more settings, i want to call another Viewcontroller with:
DateChangeController *theController = [self.storyboard instantiateViewControllerWithIdentifier:#"dateChangeController"];
[self presentViewController:theController animated:YES completion:^{NSLog(#"View controller presented.");}];
And some clicks later i return with a segue (custom:)
NSLog(#"Scroll to Ticket");
[self.sourceViewController presentModalViewController:self.destinationViewController animated:YES];
My Problem:
After returning to my main ViewController, viewDidLoad is called (everytime).I read, that the ARC releasing my mainView after "going" to the other ViewController and calling the viewDidUnload Method, but i want to keep all my data and tables i initialize at the beginning..
Any solution? Thank you very much!
The problem is that you are doing this:
main view controller ->
date change controller ->
a *different* main view controller
In other words, although in your verbal description you use the words "returning to my main ViewController", you are not in fact returning; you are moving forward to yet another instance of this main view controller every time, piling up all these view controllers on top of one another.
The way to return to an existing view controller is not to make a segue but to return! The return from presentViewController is dismissViewController. You do not use a segue for that; you just call dismissViewController. (Okay, in iOS 6 you can in fact use a segue, but it is a very special and rather complicated kind of segue called an Unwind or Exit segue.)
If you do that, you'll be back at your old view controller, which was sitting there all along waiting for your return, and viewDidLoad will not be called.
So, this was a good question for you to ask, because the double call of viewDidLoad was a sign to you that your architecture was all wrong.
I think you're taking the wrong approach - viewDidLoad is supposed to be called when it is called - it's a notification to you that the view is being refreshed or initially loaded. What you want to do is move that table initialization code somewhere else, or, at least, set a Boolean variable so that it is only called once. Would it work to create an object that has your table data when viewDidLoad is first called, then to check it to see if it's already been called?
I've recently started developing for the iPhone and so far I'm doing pretty good but there's this basic pattern I really don't seem to get.
Say, I have a TabBar with two views and a custom delegate protocol, thus my structure is the following:
AppDelegate.h/.m
myDelegateProtocol.h
FirstViewController.h/.m
SecondViewController.h/.m
MainView.xib
FirstView.xib
SecondView.xib
Now I want to achieve the following: I placed a button in the FirstView.xib and I'd like the IBAction which it invokes (inside FirstViewController ofc.) to send a message to the SecondViewController ([self.delegate tellSecondViewContrToSayHi]) and invoke another method which simply prints a log into the console saying "hi I'm here."
So far I know what I need to do in theory:
Specify the protocol.
Implement the protocol in the SecondViewController.
Create an id< myDelegateProtocol > delegate inside my FirstViewController,...AND last but not least:
Set the self.delegate = secondViewControllerObject.
Now, nr.4 is where the problem's at. How on earth do I link the delegate to the other viewController? I mean I'm not the one instantiating the views as the tabBar kinda does that for me,... any advise? Or am I just way too tired to notice a really stupid thing I did somewhere?
Theoretically the same question also applies to the target:action: thing,... I mean, how do I define the target?
Thanks a lot,
wasabi
You have the right idea, assuming that you want relatively tight coupling between these controllers via that delegate protocol.
Since neither controller knows about the other until that delegate property is set you need to have some object which has a reference to both of them wire up that relationship. In your case that's probably the application delegate which can create both controllers, set one as the delegate of the other, and pass both along to your tab bar controller.
What you might actually want is to have the app delegate give both controllers a reference to some shared model object. Your FirstViewController can update that model when you tap a button and your SecondViewController can observe changes to the model to update it's display (or just update its view when it appears based on the current model state). That way your controllers don't need to know anything about each other.
My understanding about passing data back to a delegate completely revolves around making a new view controller and having it conform to a protocol.
I am trying to get a time input back from a UIDatePicker set with the UIDatePickerModeCountDownTimer mode and I am running into issues.
Inside of Main1.m I create a UIActionSheet *action, and set everything up so that it presents itself with a UIDatePicker on a click. Inside of Main.m I also say:
main.delegate = self;
If this were not a UIActionSheet, I would make a protocol reference inside the new ViewController and then have the new vc pass data to a method that Main has, but I can't do that with a UIActionSheet!!
What am I missing? I assume there is something inherently different about Action Sheets, ut I can't figure it out.
Thanks for your help!!!
EDIT:
Sorry! I was giving a generic name to my view controller. It isn't actually Main.m, its FirstViewController.h/m
I didn't realize that my generic reference was getting mixed up with the Main.m file that is completely different than a vc.
I don't exactly understand why you're putting your delegate assignment in Main.m. I assume that you're setting up your UIActionSheet in a ViewController, and launching it from there. In this case, your ViewController is your delegate object. So you need to make sure that your ViewController implements the UIActionSheetDelegate. ie:
#interface SomeController : UIViewController <UIActionSheetDelegate>
Then you simply implement the required methods of that delegate in your view controller class, and that should do it. If I'm missing something about how you're implementing this, then you need to provide more code examples to examine.
I hope that you will succeed in at least a little to clarify me how and what to do, I'm sure I'm wrong, so I really need an expert opinion.
I have two viewcontroller together with nibs what I want is to call function that is in first class from another ViewController, the problem is that another viewcontroller manages to call this function but the only thing I can see that is done is NSlog which outputs in the console (which I put in that position to know that the function is called)
example:
FirstViewController.m
-(void)drawingFunction:(NSString*)inputText{
NSLog("Feature was launched");
/* showing stuff in FirstView.xib */
}
SecondViewController.m
-(void)turnOnFunction:(id)sender{
FirstViewController *stuff= [[PrviViewController alloc] init];
[stuff drawingFunction:#"ShowAll"];
}
Basically when I call that function in the PrviViewController.m meaning without reference to the outside e.g.
[self drawingFunction:#"ShowAll"];
everything is well displayed, but when I try to call this function from SecondViewController.m all I see is just a "feature was launched" on the console
I really don't know what to do ...
if i get you right, the FirstViewController is on top of the view controller hierarchy (either within a navigation controller or presented modal)? So, if that is the case just creating an instance of SecondViewController and calling a function which should change the user interface on the view which corresponds to SecondViewController will do nothing at all.
You have to present the SecondViewController and its view with presentModalViewController:animated: for instance. After that the view of SecondViewController will be shown and you can do any changes on that view. Also calling the method drawingFunction: will act as you expect it.
Cheers,
Andreas
You're confusing instances with classes. You don't send messages (call functions) to classes, you send them to instances.
In this case, you have two entirely separate instances of FirstViewController. The first is created by loading the nib and the second is created in -[SecondController turnOnFunction:]. The drawingFunction: message is being sent to the second instance when you want it to be sent to the first.
You need to link the nib instance of FirstViewController to the SecondController instance. You can do that with an outlet in interface builder or you can assign it when you create the display the SecondController.