I give an example:
I am using two view controllers, lets name it Home and Sales. Firstly, i navigate from Home To Sales using push. In Sales view controller i have globally declared an int value and assign it to zero. Like this:
int example_int = 0;
After that, there is some process that going in Sales View Controller, and example_int value changed, for example it has value of 2. Next, it navigate back to Home using pop. For testing purpose, i navigate back to Sales and i NSLog example_int, it gave the same value of 2.
This gave me problem initially. But i have solved it by using func: viewWillDismiss and assign the example_int to 0(default value). So for now, i m just curios what is going on here.Thank you.
The global variable will persist through out the app life cycle, if the use of example_int variable is limited to sales view than in that case you should create example_int as the member variable of sales view controller. If at all there is a requirement to keep the example_int variable as global than in that case you need to reset the value of example_int to 0 as per your requirement (in your case inside viewDidDisappear or viewDidUnLoad methods of sales view controller).
Related
I have a pure dynamic page page1VC (which is parent) where i have few buttons which takes them to page2VC, page3VC, page4VC
There is next button and back button in every view controller (no back button in p1VC as this is parent)
I can navigate to any viewController from any other vc i.e, from p1VC -> p2VC -> p4VC -> p3Vc
on tap of back in any view controller, that takes me to p1VC
page1VC gets all info to display from API and stores in variable p1APIInfo
On tap of back button from page2VC or page3VC or page4VC --> this should take me to page1VC
My question is:
As my page1VC is pure dynamic, on 1st landing of this page, i get all info from API
When I navigate to page4VC and on tap of back it should take me to page1VC and here i dont want API to be called anytime when user taps back button
As of now i have a dummy variable in page1VC which is copy of p1APIInfo variable (say dummyAPIInfo)
Each time when i tap next im passing that variable to another VC, and on tap of back from that VC im passing back that variable. So basically this variable is to only transport data to other VC and get it back to page1VC on tap of "back" button. Im not using any data in this dummy variable in page2VC/page3VC/page4VC
However this works, but this is not best practice.
I can think of saving my page1 data in userdefaults/singleton but im looking for more optimizing solution
pls suggest how to handle
So to summarize: I want my API call to happen only once i.e., during 1st time landing..after that whenever user visits/tap back button from some other page, i need a way not to call API. It should use same data that user gets during 1st API call.
Hope I'm clear with my question. Pls advice
Make sure you do the calls in a function that isn't called multiple times. For instance, if your api calls are in the viewWillAppear method, you'll do a fetch every time you pop your navigation stack. Putting the api calls in viewDidLoad will ensure that your api calls only happen once.
As for a way to transport data back to page1...
You could create a custom model that page1 relies on, and inject that model to other pages
You could use the delegation pattern to pass back information
You could use notifications and observers to broadcast and catch updates
You could pass a reference of page1 to any other page and allow other pages to make updates to page1 on its behalf
All 4 strategies are viable, and really depends on your use case and what other things you need in your app. You could even use a singleton. UserDefaults seems like a bad idea though, since your use case is to update a model for a view controller.
I am currently developing a subscription app.
I currently have 6 View Controllers to which have different options on.
For example - Name - Amount - Date etc.
Once the user completes these, I want it to create a new view controller with this information on it.
So once they go back onto the main screen, they will be able to swipe left and it will show their subscription.
All I want to know is, is there a way I can create a new view controller with their information on it once they press a complete button on the Date page?
Transferring data to a view controller is the easy part. I am more wondering on how I can create a new view controller when they try and add another Subscription, if that makes sense.
If not is there a way I can do this?
You have two options that I can think of. I am sure there are more, but these may help.
You could create a global instance of a struct that is your "subscription to add". You could then update the values for each property of this struct (e.g. name, amount, date, etc.) after each VC is dismissed
You can pass the data your user is generating to each VC through prepareForSegue. This is slightly redundant so I would recommend doing the first method. For the record, this segue method would look something like this:
VC 1 Dismissed: Pass Name to VC2
VC 2 Dismissed: Pass Name and Amount to VC3
VC 3 Dismissed: Pass Name, Amount, and Date to VC4 etc......
Once you have all of the information, you can show the last VC and just set the labels and such to the values of your struct, or the values you passed through the segue.
Edit: Further Information on Option 1
So if you made a struct like this:
struct UserToAdd {
static var name: String = String()
static var amount: Int = 0
static var date: Date = Date()
}
with all of the properties that you want a subscription to have, then you can store this information in this struct as you progress through each VC.
For example, if your first VC got the subscription name, then when your "prepareForSegue" function is called, as you are about to move to the second VC, then you could do something like this:
UserToAdd.name = "My Subscription Name"
Of course the string you assign to this name would depend on the data the user enters and such, but I hope it illustrates my point. It would be a similar process for each initial VC, but then once you have all of the data you need, you could just then call this data when your last VC loads, and set it to the text of a label or something like this:
var nameLabel = UILabel()
nameLabel.text = UserToAdd.name
self.view.addSubview(nameLabel);
Let me know if you have any further questions.
I am basically trying to implement a video conference functionality using opentok.
I have two view controllers.
Class A that has a grey image(to tell user is offline).
It calls setsession from class B to establish the session.
uses ClassADelegate and implements setUserOnlineImage that sets the class A grey image to green.
Class B holds a method useronline.
Has a class method sharedinstance that gives out the singleton instance of the class
viewdidload ->sets a variable type = 2;
setsession ->sets a variable type = 1;
It also has a protocol "ClassADelegate"
Protocol ClassADelegate has method setUserOnlineImage.
Has a callback method session:streamCreated: that is called when a subscriber is created and setupPublisher that publishes the video
The flow is like this.
first Class A calls the setsession from Class B to establish session.
Then when a connect button is clicked the viewdidload is called and then the setupPublisher is called, view is modified loaded and all that.
Now when a subscriber tries to connect session:streamCreated: is called. here when i try to print type value it comes as one, likewise many other variables also become nil which inturn results in just giving the audio and the video isnt seen.
where as if first session:streamCreated: is called (first video is received and then connect is clicked) the flow works fine and the print statement in session:streamCreated: correctly prints type value as 2.
Someone help me figure out whats happening.
I want to know why the type value is getting changed & various other variables become nil. This is preventing the video from showing. Am i missing something? Is any other instance is been taken(but I am using a singleton instance)?
The flow you describe doesn't follow any of the known patterns of how UIViewControllers should behave. Specifically, you shouldn't need to use a singleton instance of a view controller. I think you need to reconsider the architecture, specifically the relationship between these two view controllers.
By the way, the viewDidLoad method is called on the view controller as soon as its view property becomes available, which can be before its on the screen. If the view controller is loading its view from a storyboard or nib, viewDidLoad is called as soon as that view is ready. Otherwise if you are implementing loadView, viewDidLoad is called after that method is finished.
Can you describe what Class A and Class B are trying to accomplish? It sounds like Class A is a view controller for some type of status view that shows a user's online/offline status. Class B sounds like its the OTSessionDelegate as well as the view controller for where the publisher/subscriber views will be placed. Why are these not the same View Controller? (generally view controllers are meant to control a "screenful" of content, unless you are using View Controller Containment). If these two view controllers are not on the screen at the same time, can you use a segue to pass data between them when the transition occurs?
UPDATE:
The additional information is useful for me to give you a recommendation. The thing I'm still uncertain about is if you actually do have these 2 view controllers' views on screen at the same time. This solution should work in both cases.
Outside of a segue, one view controller should not really be calling another view controller's methods directly (so calling setsession as you described is a bad idea). You shouldn't even set one as the delegate of another. At most they should share a Model object to communicate. The OTSession can be seen as a Model object. The challenging limitation is that when using the delegation pattern, only one object (you chose Class B) can be informed of updates. Rather than using the delegation pattern, I think you should use NSNotifications. In order to accomplish this, you should "wrap" the OTSession model in your own model object, setting your own model object as the delegate. Then you can notify both controllers of interesting changes as they happen. I've created a diagram to demonstrate:
In this diagram, all the downward solid arrows are owning references. VideoConference would be your own class and it would implement the OTSessionDelegateProtocol. On initialization, the VideoConference instance would create and own an OTSession instance. When something happens that Class A or Class B need to know about (such as the remote user coming online), VideoConference can send an NSNotification, which both controllers can be observers. Here is a useful article about NSNotifications.
I have 2 viewControllers (NewTicket1Controller and NewTicket2Controller). View 1 has a text field named 'ticket' and view 2 wants to access that value.
Here is my code in View 2.
NewTicket1Controller *screen1 = [[NewTicket1Controller alloc] init];
NSLog(#"%#", screen1.ticket.text);
My NSLog statement above returns null for the ticket textfield value. But it's not null. If I switch back to view 1 I can see that there is a value in that field.
Can I not retrieve a variable like this?
When you instantiate a new NewTicket1Controller, all of it's properties are initialized to their default values. This does not give you a reference to any existing NewTicket1Controller objects. If you are using storyboards, you can pass it to the other view controller in prepareForSegue, or if you are not using storyboards, you can programatically pass it to the new view controller when it is created, assuming it is created from the NewTicket1Controller.
No need to initialize you view to access it. If you want to send text contained in textfield to another view..You need to store that ticket text field value into a string of other view controller..
At NewTicket2Controller take property with NSString with name ticketString and synthesize it...Then you can use that reference for storing value of ticket at NewTicket1Controller
At button action while switching to NewTicket2Controller..Put some code at NewTicket1Controller
NewTicket2Controller *screen2 = [[NewTicket2Controller alloc] initWithNibName:#"NewTicket2Controller" bundle:nil];
screen2.ticketString=self.ticket.text;//if you propertise the ticket textfield
NSLog(#"%#", screen2.ticketString);
Hope it helps you..
You just created and inited screen1. Any and all values will be nil or initialized.
A few things:
You want to try to keep the data (model) separate from your views and controller when possible.
You're going to have to provide some connection between the 2 view controllers.
One approach is to set up one as a weak link to the other.
Example for NewTicket2Controller
#property (nonatomic, weak) NewTicket1Controller *delegate;
And then when you create NewTicket2Controller you would assign self.delegate = screen1
After that you could access methods using the delegate.
(Ideally you'd setup a protocol for the delegate)
Others have given you partial answers. Let me state everything at once.
First, never try to manipulate another view controller's view objects directly. That is serious violation of the "encapsulation" principle of object oriented programming. You should treat a view controller's views as private, and add properties or methods to communicate between view controllers.
Second, you are creating a brand new instance of your view controller and expecting to be able to use that new view controller instance to alter settings in an existing view controller. This is like buying a new car that is a perfect match for your existing car, setting the radio station on that new car, and then wondering why the radio station on the old car doesn't change. They are different cars! They are different objects! They may be feature-for-feature identical, but they are different instances of the same object. If you had an identical twin, it is still a different person, right?
You need a way to get a pointer to your existing NewTicket1Controller object. How you do that depends on how your program is set up. Post some info on how you are setting up your view controllers. Are you using a navigation controller? Is NewTicket1Controller your root view controller? How are you getting from view controller 1 to view controller 2? A segue? (assuming you're using storyboards. Tell us if you're not.)
I have a app, where I've a tabview controller. All the data is dynamic, and when I enter on one tab, the data is loaded, but if I change my tab and come back to the initial tab, I haven't lost the data on it, what is awesome. My problem now is that I've built a new viewcontroller (outside the tabs) and when I go into it, and come back to the tabs I've lost all my information!
Is there any way to retain the initial data? So there when the user goes to that another view, and comes back, don't have to lose the data.
And another question. Is there anyway, to define variables that are available to every viewcontroller's in the app?
Data will not change when you move from one tab to the other
You will need to check if you have some special code in your viewWillAppear, if you load the data in this function you should know that viewWillAppear gets called when you travel tabs
About the global Data, you could define them in your appDelegate class, add properties to the appDelegate and then you can access them like this
//Add this on the header of your class
#import "MyAppDelegate.h"
//Then access the delegate like this
MyAppDelegate *myAppDelegate = [UIApplication sharedApplication].delegate;
//Access your variables
myAppDelegate.myVariables;
What is this general data? If it is objects, I would call retain. But if it was a data type, try making is static and make a method returning it. Or you could wrap it in an object, (like NSNumber for example if it was a float, double or int etc.) then call retain to that.