Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

Setting parameters on one tab and show it in another tab. (Tabbed Application)

arlekinarlekin Posts: 29Registered Users
Hi!

I use Tabbed Application for my app.
In the first tab I set the date using the Date Picker.
In the second one I show this date on the text Label.
Unfortunately this 'set' doesn't work - it doesn't show my set date from the 1st tab to my 2nd one.

I would like to know how to 'refresh' the tab with set parameters.

Best regards! ;)

Replies

  • dapisdapis Posts: 307Registered Users
    Keep a singleton class available for shared data - some people use the app delegate. Then save a result from one tab to the shared class and read it from the shared class in the other tab.
    If you choose to use the app delegate the code looks akin to this:

    AppNameAppDelegate *myAppDelegate =[[UIApplication sharedApplication] delegate];

    //Save the data from one tab
    myAppDelegate.thedata =.....

    //read the data from the other
    theParam = myAppDelegate.theData

    Google "[[UIApplication sharedApplication] delegate]" for actual examples of this approach.
  • arlekinarlekin Posts: 29Registered Users
    dapis said:

    Keep a singleton class available for shared data - some people use the app delegate. Then save a result from one tab to the shared class and read it from the shared class in the other tab.
    If you choose to use the app delegate the code looks akin to this:

    AppNameAppDelegate *myAppDelegate =[[UIApplication sharedApplication] delegate];

    //Save the data from one tab
    myAppDelegate.thedata =.....

    //read the data from the other
    theParam = myAppDelegate.theData

    Google "[[UIApplication sharedApplication] delegate]" for actual examples of this approach.

    Hi! thanks for reply!

    Unfortunately I use AppDelegate for my app. Unfortunately to set the date in the label I have do click button, etc. It doesn't do by itself.
  • Duncan CDuncan C Posts: 8,019Tutorial Authors, Registered Users
    arlekin said:

    dapis said:

    Keep a singleton class available for shared data - some people use the app delegate. Then save a result from one tab to the shared class and read it from the shared class in the other tab.
    If you choose to use the app delegate the code looks akin to this:

    AppNameAppDelegate *myAppDelegate =[[UIApplication sharedApplication] delegate];

    //Save the data from one tab
    myAppDelegate.thedata =.....

    //read the data from the other
    theParam = myAppDelegate.theData

    Google "[[UIApplication sharedApplication] delegate]" for actual examples of this approach.

    Hi! thanks for reply!

    Unfortunately I use AppDelegate for my app. Unfortunately to set the date in the label I have do click button, etc. It doesn't do by itself.
    As the other poster suggested, add a property to your app delegate (or better yet, a data container singleton) to hold the value you need to pass to the other tab.

    In the other view controller, read the value from the app delegate (or singleton) and copy it to your label in the viewWillAppear method.

    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • Manish915Manish915 Posts: 24Registered Users
    If you do not want to use either appDelegate or Singleton class, you'll have to get the value from the actual view controller in which you set the date.

    Lets say you have two View Controller objects in TabBarController object
    -VC1 for first tab (where u store date)
    -VC2 for second tab. (where u retrieve date)

    Note: VC1 & VC2 may (or may not) be of same class.

    For VC1
    - set its View tag to some value, say 55. This would be later used to identify the ViewController object associated with this View.
    - create a retained variable to store date value, say 'mDate'. Also create a property for this variable to enable access from outside.

    Set mDate in VC1 where u intend to.

    While in VC2, when you want to get the 'mDate' set in VC1

    - get TabBarController object.
    - get ViewControllers Array from TabBarController object.
    - for each ViewController in ViewController Array, check for class of ViewController.
    - when ViewController of desired Class Type is found, check for tag of ViewController's view. (to ensure that u get the ViewController object in which you set the date)
    - if the tag matches, retrieve 'mDate' variable value from the ViewController object.

    That would be a lot of code compared to appDelegate approach where you only have to create a variable and a property in appDelegate. and two lines of code to get that value wherever you want.

    How are you setting and retrieving the date variable in ur code?
    Post edited by Manish915 on
  • Duncan CDuncan C Posts: 8,019Tutorial Authors, Registered Users
    Manish915 said:

    If you do not want to use either appDelegate or Singleton class, you'll have to get the value from the actual view controller in which you set the date.

    Lets say you have two View Controller objects in TabBarController object
    -VC1 for first tab (where u store date)
    -VC2 for second tab. (where u retrieve date)

    Note: VC1 & VC2 may (or may not) be of same class.

    For VC1
    - set its View tag to some value, say 55. This would be later used to identify the ViewController object associated with this View.
    - create a retained variable to store date value, say 'mDate'. Also create a property for this variable to enable access from outside.

    Set mDate in VC1 where u intend to.

    While in VC2, when you want to get the 'mDate' set in VC1

    - get TabBarController object.
    - get ViewControllers Array from TabBarController object.
    - for each ViewController in ViewController Array, check for class of ViewController.
    - when ViewController of desired Class Type is found, check for tag of ViewController's view. (to ensure that u get the ViewController object in which you set the date)
    - if the tag matches, retrieve 'mDate' variable value from the ViewController object.

    That would be a lot of code compared to appDelegate approach where you only have to create a variable and a property in appDelegate. and two lines of code to get that value wherever you want.

    How are you setting and retrieving the date variable in ur code?

    Gack!

    That is very bad programming practice. You should never access a view controller's views from outside that view controller. It breaks the encapsulation of that view controller.

    In the MVC design pattern, a controller object should be the only object that manipulates the view objects that it manages. When you have one view controller mucking around in another view controller's views, it means that if you change either view controller, you have to change the other one as well, and are likely to break things at some point in the future.

    You also face problems if you have 2 view controllers and the second view controller hasn't been displayed to the screen yet. In that case, it's views may not even exist, so trying to save data into a view fails because the outlet is nil.

    If you're going to have the 2 view controllers pass data directly, you should set a data property and query it.

    In the OP's case, add an NSDate property to the view controller that has the picker. Then in the second view controller, get a pointer to the first view controller and read it's date property. That accomplishes the same thing in a much cleaner, less fragile way.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • Manish915Manish915 Posts: 24Registered Users
    Duncan C said:


    You also face problems if you have 2 view controllers and the second view controller hasn't been displayed to the screen yet. In that case, it's views may not even exist, so trying to save data into a view fails because the outlet is nil.

    AFAIK the data was being saved when the user was presented with a view where s/he selected the date from a picker. In that case the view is already initialized so trying to save data using this view's viewController object will not fail.
    Also when using TabBar, the ViewController are initialized before they are added to a TabBarController. If the ViewControllers are initialized properly, the question of view outlet being nil does not arise.
    Duncan C said:


    If you're going to have the 2 view controllers pass data directly, you should set a data property and query it.

    Thats exactly what i meant by
    create a retained variable to store date value, say 'mDate'. Also create a property for this variable to enable access from outside.
    Duncan C said:


    In the OP's case, add an NSDate property to the view controller that has the picker. Then in the second view controller, get a pointer to the first view controller and read it's date property. That accomplishes the same thing in a much cleaner, less fragile way.

    How would one get a pointer to the first viewController in the second View Controller? The approach i used was to find the first ViewController by looking inside TabBarControllers ViewController. Then to ensure that i had the correct Object, check its Class. Then to further make sure that I'm not getting some other object of same class, checked its view tag property, that I had set explicitly (we can use any iVar here that exists in all controllers and which can be set and queried to check for an object later). The check would fail for other controllers if their view is nil or if their tag is different.

    Thats the only way I could think of without using singletons or appDelegate.
    I strongly favor clean coding practices. If there is a better approach to this, it will be my pleasure to know about it so that i could use it in my future codings

    Regards.
    "I have learned a lot here and will continue to do so..."
    Post edited by Manish915 on
  • BrianSlickBrianSlick Posts: 9,302Tutorial Authors, Registered Users
    Manish915 said:


    AFAIK the data was being saved when the user was presented with a view where s/he selected the date from a picker. In that case the view is already initialized so trying to save data using this view's viewController object will not fail.
    Also when using TabBar, the ViewController are initialized before they are added to a TabBarController. If the ViewControllers are initialized properly, the question of view outlet being nil does not arise.

    It's not a matter of initialization. Views are not loaded until they are requested. Creating a view controller does NOT create a view. When you go to put that view controller's view on the screen - such as by switching tabs - then the view will be loaded.

    Even if the view outlet was populated initially, you still have a potential problem thereafter. View controllers unload their views a lot. The only view controller's view that is pretty much guaranteed to remain alive is the one that is currently on screen. Tab #1 will be fine, but #2, #3, #4, etc. could all unload at any time, such as in response to a low memory warning. When this happens, a well-designed VC will nil out any IBOutlets. Even if a VC leaves the IBOutlets populated in such a condition, it does not matter. When the view is reloaded, those IBOutlets will be repopulated with NEW objects from the xib. IBOutlet != nil does NOT mean that the IBOutlet/view is on screen, or will be on screen the next time you go there.

    This is not something you need to trust anybody's word on, you can easily verify for yourself. Throw some VCs in a tab bar controller (or any managing controller, for that matter), throw some logs in viewDidLoad and viewDidUnload, and see what happens. Trigger some memory warnings and see what happens.

    In your particular example, by checking the view's tag, you would therefore have to load the view. So you most likely indeed will find a populated IBOutlet if you check. But it happened because the view was loaded, not because the VC was initialized.

    Another potential option is to use notifications.
    Manish915
  • uzauziuzauzi Posts: 11New Users
    It's not a matter of initialization. Views are not loaded until they are requested. Creating a view controller does NOT create a view. When you go to put that view controller's view on the screen - such as by switching tabs - then the view will be loaded.
    it my opinion also
    Domeledljeffery
  • Duncan CDuncan C Posts: 8,019Tutorial Authors, Registered Users

    You said:
    I strongly favor clean coding practices. If there is a better approach to this, it will be my pleasure to know about it so that i could use it in my future codings.
    So set up a data container singleton. That's much cleaner than all the nonsense you're trying to do.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • Manish915Manish915 Posts: 24Registered Users
    Duncan C said:


    So set up a data container singleton. That's much cleaner than all the nonsense you're trying to do.

    You missed that I said "without using app delegate or singleton".
    Dapis had already mentioned the two possible solutions: appDelegate and singleton.
    BrianSlicked added one more possible solution: Notifications

    Mine was a possible way to get the data, though not the best one. And while its true that accessing view property when view is not likely to be loaded can cause problems, the check for view.tag can be eliminated if all VCs are of different class.
  • Duncan CDuncan C Posts: 8,019Tutorial Authors, Registered Users
    Manish915 said:

    Duncan C said:


    So set up a data container singleton. That's much cleaner than all the nonsense you're trying to do.

    You missed that I said "without using app delegate or singleton".
    Dapis had already mentioned the two possible solutions: appDelegate and singleton.
    BrianSlicked added one more possible solution: Notifications

    Mine was a possible way to get the data, though not the best one. And while its true that accessing view property when view is not likely to be loaded can cause problems, the check for view.tag can be eliminated if all VCs are of different class.
    Your post essentially says "I strongly favor clean coding practices, but I need help coming up with a contorted way of doing something because I don't want to follow people's recommendations on what those clean practices are."

    Given that the tabs in a tab bar application don't have direct access to each other, you have to go through contortions to link from one to another. Your post about iterating through the list of tabs in the tab bar controller and using some sort of tagging system to find the right one is not clean coding practices. It's a hack.

    You should NEVER refer to a view controller's views from an outside object. That is a case study in bad coding practices. Really. Very bad idea.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
Sign In or Register to comment.