views:

597

answers:

3

I would like to get at

- (void)applicationWillTerminate:(UIApplication *)application

a variable from a view controller class. I have build an tabbar application and only added the tabbar controller to the appdelegate.

[window addSubview:tabBarController.view];

How can i get an variable from the TestViewController:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface TestViewController : UIViewController {
    IBOutlet UILabel *testLabel;
    NSString *currentString; //Value that i want to save at applicationWillTerminate
}

@property (nonatomic, retain) UILabel* testLabel;
@property (nonatomic, retain) NSString* currentString;

@end
A: 

Not 100% sure what you are asking for but here is a guess:
UITabBarController's have a property called viewControllers which return all view controllers associated with the tabbar.

Assuming that the TestViewController was the first tab you could get to it by:

- (void)applicationWillTerminate:(UIApplication *)application {
    TestViewController* test_view_controller = [tabBarController.viewControllers objectAtIndex:0] ;
    NSString* value = test_view_controller.currentString ;
}

Note this would break if you decided to later move the TestViewController to a different position in the tabbar.

-- Edit -- Check all controllers and get the string from the controller that is of type TestViewController.

NSString* value = nil ;
for ( id unknownController in tabBarController.viewControllers ) {
  if ( [unknownController isKindOfClass:[TestViewController class]] ) {
     value = ((TestViewController*)unknownController).currentString ; 
  }
}
// value should be the value of the string.
Eld
That is what i wan't, but when i try your code i get the folowing error when i close the app:*** -[UINavigationController currentString]: unrecognized selector sent to instance 0x4313b80*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UINavigationController currentString]: unrecognized selector sent to instance 0x4313b80'
x2on
it may be at a different tab index. You could iterate over them all and check to see if its of type TestViewController. NSString* value ; for each controller in tabview if ( [unknownController isKindOfClass:[TestViewController class]] ) { value = ((TestViewController*)unknownController).currentString ; }
Eld
+1  A: 

It's somewhat incidental that TestViewController hasn't been dealloc'd by the time you reach applicationWillTerminate - it might make sense to store that value a level higher in your application. That approach would be to always store currentString in the UIApplicationDelegate so that you don't have to fetch it later:

@implementation TestViewController
- (void)setCurrentString:(NSString *)currentString {
    ((MyAppDelegate *)[[UIApplication sharedApplication] delegate]).currentString = currentString;
} 
@end
dbarker
Thanks this works fine, but the currentString value is changing every second. Is this ok or is it not so good to set the currentString every second to the AppDelegate?
x2on
it's probably not ideal - not because it's the UIApplicationDelegate, but because sending three messages every second is expensive (sharedApplication, delegate, setCurrentString). If TestViewController can do whatever it needs to do with currentString at close - you could register it for the UIApplicationWillTerminateNotification.
dbarker
Ok i rewrited my code, so i can register the UIApplicationWillTerminateNotification and make the actions there. Thanks for this hint!
x2on
+1  A: 

Expanding on dbarker's answer, it sounds like what you really need is to save the currentString value in your data model. The proper place to do that is in the viewController itself.

If your data model is just that one string, you can create a property in the app delegate to hold it. Then the viewController writes to the app delegate property whenever the value of currentString changes in a view and/or its value when the view closes.

This way, the data (which is the entire point of the app anyway) is always in place when the app closes regardless of how many views you open.

It is the proper role of controllers to move information from the interface to the data model. Strictly speaking, the viewController shouldn't store any data at all beyond that needed by the interface itself. That should be a property of the data model which the viewControllers set by sending a message to the data model object with the values taken from the interface.

In this case, you would not have a currentString property in your view controllers. Instead they would have a property that is just a reference to the data model's currentString property. The view controllers would continuously update that property but would store nothing themselves.

The advantage of this design is obvious. If you need the value anywhere in your app, you have one location and one call to get it. No single part of the app needs to even know of the existence of any other part of the app save for the data model.

TechZen