I need to initialize an object of an object in my AppDelegate at startup. Whenever I try to access the ivar somewhere else all that is returned is null.
What I'm doing can be simplified as
//AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate> {
NSString* someString;
}
#property (nonatomic, copy) NSString* someString;
and then in the AppDelegate.m
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
someString = #"Hello World!";
NSLog(#"%#",someString);
}
This is what I do when I access the NSString-object
//ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#",delegate.someString);
}
The output text is
2012-09-30 22:26:45.125 Labor3[22524:f803] Hello World!
2012-09-30 22:26:45.127 Labor3[22524:f803] (null)
without any warnings or errors.
The problem I'm having is a bit more complicated but the essentials stay the same and I can't even get the above example to work. Any hint is appreciated.
Add
#synthesize someString;
After
#implementation AppDelegate
in your app-delegate .m file.
You should use _someString instead of someString or use Andrey's answer solution, in your code property someString and ivar someString haven't any connection
Related
I have a navigation controller residing inside a tab bar controller and whenever I try to access a class from a class within the navigation controller all my values return (null).
This is how I'm trying to do it.
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate> {
NSString *searchQueryA;
}
#property (strong, nonatomic) NSString *searchQueryA;
ThirdViewController.h
#import "MasterViewController.h"
#import "AppDelegate.h"
#class MasterViewController;
#interface ThirdViewController : UIViewController {
code
}
#property (strong, retain) MasterViewController *masterViewController;
ThirdViewController.m
- (IBAction)showDetail:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
appDelegate.searchQueryA = _searchField.text;
masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[self.navigationController pushViewController:masterViewController animated:YES];
}
MasterViewController.h
#import "AppDelegate.h"
#interface MasterViewController : UITableViewController
{
NSString *searchQueryM;
}
#property (nonatomic, strong) NSString *searchQueryM;
MasterViewController.m
AppDelegate *appDelegate = [[AppDelegate alloc] init];
searchQueryM = appDelegate.searchQueryA;
NSLog(#"%#", searchQueryM);
And in the log I can see that searchQueryM is (null). If I try to access the variable in AppDelegate from another class, that isn't involved with navigation controller, then it shows perfectly fine. What am I missing?
If you need to see more code I'd be happy to provide it.
EDIT:
For legibility I'll post code changes here:
I have the delegate in my AppDelegate.h
As Leonardo pointed out I only alloc'd and init'd my AppDelegate. I changed that snippet to this:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
searchQueryM = appDelegate.searchQueryA;
but still no go as searchQueryM still is (null).
This is what I do with searchQueryM
MasterViewController.h
#interface MasterViewController : UITableViewController
{
NSString *searchQueryM;
}
#property (nonatomic, strong) NSString *searchQueryM;
MasterViewController.m
#synthesize searchQueryM;
I'm fairly new to Objective-C (as well as OO-programming) and should probably read a book on it, but it seems to me like there isn't a lot more to it than that. Do correct me if I'm wrong.
EDIT 2
ThirdViewController.h
#interface ThirdViewController : UIViewController {
UITextField *_searchField;
}
#property (nonatomic, strong) IBOutlet UITextField *searchField;
ThirdViewController.m
#synthesize searchField = _searchField;
...
- (IBAction)showDetail:(id)sender {
_code_
NSLog(#"%#", searchField.text);
_code_
If i type in "asd" in the searchField textfield and output it with the log I get "asd".
}
Why are you alloc init your AppDelegate ?
The AppDelegate should be accessed with:
[[UIApplication sharedApplication] delegate]
We should see how you normally initialize searchQueryM, you are getting null, probably because the AppDelegate get only allocated and init, but the logic that initialize its properties never gets called.
I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...
I have created a tab based application having 4 tabs and 4 views respective to these tabs.
I have a string in first view and when I printing this string in second view it printing null.
In first view.h
NSString *dateString;
#property(nonatomic,retain) NSString *dateString;
In first view.m
#synthesize dateString;
dateString=button6.titleLabel.text;
NSLog(#"dateString:%#",dateString);
In second view.h
NSString *dateString;
#property(nonatomic,retain) NSString *dateString;
In second view.m
#synthesize dateString;
- (void)viewDidLoad { [super viewDidLoad];
NSLog(#"dateString:%#",self.dateString);
}
Add your view controllers as properties for the application delegate (if the app is a relatively simple design).
Then you can reference the properties of the second view controller from the first view controller, by way of the app delegate. (One such property could be the string you want the second VC to copy or retain.)
Create NSString variable in Application delegate class and set the Property and make synthesize that variable.
And set the #"" (blank) value in applicationDidFinishLaunching method.
For Example - my variable name is str, then initialize str in applicationDidFinishLaunching like self.str = [NSString stringWithFormat:#""];
And now you can use it in any tab *view* and set the value as per your require.
More code
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NSString *baseURL;
}
#property (nonatomic, retain) NSString *baseURL;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window;
#synthesize baseURL;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.baseURL = [NSString stringWithFormat:#""];
}
- (void)dealloc
{
[baseURL release];
[window release];
[super dealloc];
}
#end
ViewController1.h
#class AppDelegate;
#interface ViewController1 : UIViewController <UITextFieldDelegate>
{
AppDelegate *appDelegate;
}
#end
ViewController1.m
#import "AppDelegate.h"
#import "ViewController1.h"
#implementation ViewController1
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSLog(#"value - %#",appDelegate.baseURL); // Here you can set or get the value.
}
it may not be the best answer.but creating a string variable in the appdelgate and passing the variable to this from the first view and fetching it from the second view works for me
Really, did we lose focus of MVC and the most awesome of abilities that is easy to do in iPhone Development?
How about a delegate?
#protocol ViewOneDelegate
- (void)getStringVariable;
#end
#interface ViewOneModel : NSObject
{
NSString* _stringVariable;
id<ViewOneDelegate> _theDelegate;
}
#property (nonatomic, retain) id<ViewOneDelegate> theDelegate;
#end
Assign a controller to be the delegate for the ViewOneModel.
Here is a simple solution, but not the best one, Create a global variable, and just use that.
Header
extern NSString *GlobalString;
#interface GlobalVariables : NSObject {
}
#end
implementation
#import "GlobalVariables.h"
#implementation GlobalVariables
NSString *GlobalString;
#end
And now to have access to the variable just import the header in the file you want to use.
You'll probably want to check if it's initiated before you use it.
I have an App Delegate and a 3 view controllers in my project. I have a variable(a NSMutable Array) in my App Delegate which I want to access from my view controllers. So I decided to create a pointer to my App Delegate and access the variables.
Here is my code:
iSolveMathAppDelegate.h
#import <UIKit/UIKit.h>
#interface iSolveMathAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
NSMutableArray *tmpArray;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) NSMutableArray *tmpArray; // variable I want to access
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
iSolveMathAppDelegate.m
#import "iSolveMathAppDelegate.h"
#implementation iSolveMathAppDelegate
#synthesize window;
#synthesize tabBarController;
#synthesize tmpArray;
...
- (void)dealloc {
[tabBarController release];
[window release];
[tmpArray release];
[super dealloc];
}
#end
The view controller class from which I want to access the tmpArray.
referenceViewController.h
#import <UIKit/UIKit.h>
#class iSolveMathAppDelegate;
#interface referenceViewController : UITableViewController {
NSMutableArray *equationTypes;
iSolveMathAppDelegate *data;
}
#property(nonatomic, retain) NSMutableArray *equationTypes;
#property(nonatomic, retain) iSolveMathAppDelegate *data;
#end
And finally referenceViewController.m
#import "referenceViewController.h"
#implementation referenceViewController
#synthesize equationTypes, data;
data = (iSolveMathAppDelegate *)[[UIApplication sharedApplication] delegate];
//says that initializer element is not constant...ERROR!
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"equationTemplates"ofType:#"plist"];
data.tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
self.equationTypes = data.tmpArray;
[data.tmpArray release]; // obviously none of these work, as data is not set.
}
- (void)dealloc {
[super dealloc];
[equationTypes release];
[data release];
}
#end
So anyway at the line data = (iSolveMathAppDelegate *)[[UIApplication sharedApplication] delegate]; the compiler says that the initializer element is not constant.
I have scrouged the web for answers, and for all it seems to work...but no dice for me :( Can you please advice me on where I have gone wrong? I am using XCode 3.2 and iOS SDK 3....maybe the SDK is the problem.
Thank You
That line of code isn't in a method or function, so the compiler is treating it as the definition of a compile-time constant or static/global variable. Those need constant values for initialization.
You should put the assignment of data within a method. A good place would be -viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
data = (iSolveMathAppDelegate *)[[UIApplication sharedApplication] delegate];
...
}
I figured out the struct and union problem. All I had to do was change #class iSolveAppDelegate to #import "iSolveAppDelegate.h" in my referenceViewController.h file. Thanks Jonathan for your help!
In my application i want to use instance of pagecontrol in more then 3 views..so,i want to declare,#property and #synthesize should be in appDelegate..Please give some ideas to do this...
Thanks,
Mano
I never used pagecontrol, but in principle, your code would look like:
in YourAppDelegate .h
#interface YourAppDelegate : NSObject <UIApplicationDelegate> {
...
UIPageControl *pageControl;
...
}
#property (nonatomic, retain) IBOutlet ScrollingViewController *viewController;
YourAppDelegate.m:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
pageControl = [[UIPageControl alloc] init]; // or whatever is needed to set up pagecontrol
}
in one of your views:
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
//and then access the variable by appDelegate.variable