need to define a "modifiable" global variable in objective-c - iphone

I have the following issue. I have two classes that manipulate information but they are completely disconnected, i.e. I can't reach the other class.
I need both classes to use a certain value. For example, class A sets the value foo = A and class B needs to be able to read that value and rest foo to nil.
I thought about creating the variable in the main app delegate, but can't figure out how.
Ideas?!!

Global variables are generally bad idea. Based on your description i think you can use KVO to inform class B about the changes in 'foo'.
But if you relly need a global variable you can do this:
#interface YourAppDelegate : NSObject <UIApplicationDelegate> {
}
#property (nonatomic) NSString *foo;
#end
#implementation YourAppDelegate
#synthesize foo;
...
#end
#implementation ClassA
...
- (void)someMethod {
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.foo = #"NewValueOfFoo";
}
...
#end
#implementation ClassB
...
- (void)otherMethod {
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"Value of foo: %#", appDelegate.foo); //This will print: "Value of foo: NewValueOfFoo"
}
...
#end

I'm not sure what you mean by "completely disconnected". Depending on what you're trying to do, you could use NSUserDefaults
http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
or NSNotifications
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNotification_Class/Reference/Reference.html
If class A doesn't need to know about class B, you could consider delegation as well.

Why can't he just do this?
A. Add 2 new files to your project: GlobalValues.h and GloblaValues.m.
B. Open GlobalValues.h, and declare all your needed variables.
extern NSString *MyServiceName; // name of the 'service':
C. Open GlobalValues.m, and start the new file by importing GlobalValues.h, and assign values to the variables you declared in the header file:
#import "GlobalValues.h"
NSString *MyServiceName = #"MyService is called THIS";
D. In the implementation files of the classes that need to use these variables, you would put - at the very beginning:
#import "GlobalValues.h"

Related

Global variables and objects in Objective C. What is the best way?

I want to use global variables and objects for the iphone project.
I have created NSobject class and defined like below:
.h File:
#import <Foundation/Foundation.h>
#interface GlobelClass : NSObject
extern NSString *mystr;
extern NSMutableArray *Arrdata;
#end
.m File:
#import "GlobelClass.h"
#implementation GlobelClass
NSString *mystr;
NSMutableArray *Arrdata;
#end
What is the best way Or should I use singleton pattern like below link answer:
Using global variables in Objective-C
Please share thoughts?
One of the way to use global variable in the application is:
You can use App Delegate class itself :
.h file:
AppDelegate: UIResponder <UIApplicationDelegate> {
}
#property(nonatomic,strong) NSString* strUserID;
.m file:
#synthesize strUserID;
Now you can access strUserID as global variable in your UIViewController as:
ABCProjectAppDelegate *appDelegate = (ABCProjectAppDelegate*) [[UIApplication sharedApplication] delegate];
You can set value:
appDelegate.strUserID = #"Test";
Get Value:
NSString *strId = appDelegate.strUserID;
:)

How to declare a variable that can be used in both class1.m and class B.m

i have "classmap.m" and annotation.m i have a value of coordinates in "classmap.m" and i need to assign a value in the other class annotation.m.
ex:
class1.m
double start_long;
i want to give pass the value in another one class (annotation.m)
annotation.m
annotation.longitude=Start_long;
how can i do that please give some examples is there.
thanks in advance
A better, more efficient, effective and cleaner way is to use Singleton Pattern. A good approach is to keep AppDelegate cleaner and avoid keeping global variables there. Always try to use Singleton classes and objects to keep global variables.
If both classmap.m and annotaion.m are inherited from NSObject then it's simple annotation:classmap . will give access to the properties of classmap
ClassMap
#interface classmap : NSObject
#property double longitude;
#end
#import "classmap.h"
#implementation classmap
#synthesize longitude;
#end
Annoataion
#interface annotation : classmap
#property double start_long;
#end
#import "annotation.h"
#implementation annotation
#synthesize start_long;
#end
Now the assigning can be done easily in annotation.longitude=Start_long the place you need
Take the variable in the Appdelegate and access it anywhere in the project .
Access it like
Assign Value
AppDelegate *app = [[UIApplication sharedApplication]delegate];
appd.start_long = -17.002// assign some value here
Read Value
AppDelegate *app = [[UIApplication sharedApplication]delegate];
double dVal = appd.start_long ;
The Singleton pattern is a weapon which should be used sparingly as it makes a concrete dependancy on the ClassMap object for everything which uses it.
While using a Singleton will achieve what you want right now which is access to a property in ClassMap but you set yourself up for future coding issues.
What happens when you have multiple ClassMap instances for example?
Singletons are better suited to things which do universal jobs. Things which are tools. e.g [NSUserDefaults standardUserDefaults] or [NSFileManager defaultManager]
A different solution is to use Dependancy Injection which creates a direct connection between the object Annotation which needs the ClassMap object.
In brief ClassMap declares a property
#property double start_long;
you pass the ClassMap object to the Annotation object when you instantiate.
Annotation.h
#interface Annotation:NSObject
-(instancetype)initWithClassMap:(ClassMap *)amap;
#end
and…
Annotation.m
#interface Annotation() {
ClassMap *_map;
}
#end
#implementation Annotation
-(instancetype)initWithClassMap:(ClassMap *)amap {
self = [super init];
if(self) {
_map = amap;
}
return self;
}
-(void)doSomething {
self.longitude = _map.start_long;
}
#end
Another method is to use delegation.In your classmap.m declare
#protocol classmapDelegate <NSObject>
-(void)didchangeCoordinateValue:(double)longitude;
#end
annotation should confirm to this protocol and when ever the value in classmap is changed, you could get the event tin Annotation class.

How can I call the one method in all the view controllers?

How can I call the one method in all the view controllers?
One method in viewcontroller1 like,
- (void)doSearch
{
NSLog(#"Search..!");
}
I want to call doSearch method from viewcontroller2, viewcontroller3, viewcontroller4, viewcontroller5, etc.
How to do this?
You can declare it in separate class and instantiate that class in all viewControllers, or you could define this method in your AppDelegate and call in all your viewController. you could access the AppDelegate in your ViewControllers by getting its instance like this
self.appDelegate=(AppDelegate*)[[UIApplication sharedApplication]delegate];
and finally call the method like this
[self.appDelegate doSearch];
Generally it is preferable to declare all your methods or data which is shared through the application in a separate class and use this class. I usually use singelton Object class in my application, define all the shared data in that and finally access in all classes
here is example of singelton class
MyData.h
#interface MyData : NSObject
+(MyData*)getInstance;
-(void)search;
#end
MyData.m
#import "MyData.h"
#implementation MyData
static MyData *instance =nil;
+(MyData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [[MyData alloc]init];
}
}
return instance;
}
-(void)search {
NSLog(#"search");
}
#end
finally in your viewController
MyData *myData=[MyData getInstance];
[myData search];
You can declare this method in AppDelegate.h. like
- (void)doSearch;
And Implement it in AppDelegate.m like
- (void)doSearch
{
//Your Search Logic
}
Then, Create AppDelegate instance like
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Make Your Project's .pch file look like following:
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
AppDelegate *appDelegate;
#endif
Now, From Any ViewController, You can call method like:
[appDelegate doSearch];
Happy Coding.
NOTE: Personally, I avoid this kind of implementation in AppDelegate Class.
I use Singleton Object Pattern for this kind of purpose. But, Given is the quickest way.
___________EDIT____________
Add a New Class file of NSObject type: Name it CommonMethod (or whatever you want)
in CommonMethod.h
#interface CommonMethods : NSObject
+ (CommonMethods *)sharedObject;
+ (void)doSearch;
in CommonMethod.m
#import "CommonMethods.h"
#implementation CommonMethods
+ (CommonMethods *)sharedObject
{
static dispatch_once_t once;
static CommonMethods *sharedObject;
dispatch_once(&once, ^ { sharedObject = [[CommonMethods alloc] init]; });
return sharedObject;
}
+ (BOOL)doSearch
{
// Your Search Logic.
}
Now, Add #import "CommonMethods.h" to your project's .pch file.
And You are all set to go...!!!
Method Call (in any of your viewController): [CommonMethods doSearch];
Put all controllers in an NSArray *, lets say it is called controllerArray.
Then you can make all controllers perform selector with:
[controllerArray makeObjectsPerformSelector:#selector(doSearch)];
Add your method to AppDelegate.m file
- (void)doSearch
{
NSLog(#"Search..!");
}
And Add #import "AppDelegate.h" In UIViewController that you want to call :
You can call method by,
AppDelegate *del = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[del performSelector:#selector(doSearch) withObject:nil afterDelay:0];
From Any UIViewController
You may like to read below tutorial
Global functions and variables in Objective C
or You can create methods in the appDelegate class that you can access through all your app. For example, in your AppDelegate.h you have declared this method as follow:
-(void)myMethod;
In your AppDelegate.m, you define it as:
-(void)myMethod
{
NSLog(#"myMethod is getting called");
}
From any other classes (Master or Detail, etc.), you access myMethod by:
#import "AppDelegate.h"
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate myMethod];
The best way to make AbstractViewController and inside it add all your common behaviors or methods. Any ViewController will inherits from the Abstract and can call any common Method
The best way is to make a separate header file make this method a class method and you can call this anywhere in the project by importing the class.And you can include this class into your pch file so that import can be avoided from all VCs
class.h
+ (void)doSearch
{
NSLog(#"Search..!");
}
in ViewControllers
#import "class.h"
-(void)someMethod
{
[class doSearch];
}

Can't access class instance from another class

in my AppDelegate I have imported the header of a class I have created and propertied and syntesized an instance of it (in AppDelegate). Now I'm trying to access a method and a variable inside this instance from two other views. I'm relatively new to objective-c, but so far I've learned that if I do this:
AppDelegate *appdelegate = [AppDelegate new];
I will just get a fresh instance from the class inside AppDelegate, so if I set a variable from one view, I can't access it from the other. I've read that if I would do it this way:
AppDelegate *ap = (AppDelegate *)[[UIApplication sharedApplication] delegate];
It would allow me to access the existing instance. But it doesn't work.
Is the way I'm trying to do this totally wrong? Thanks a lot for your help!
UPDATE:
When I do this inside AppDelegate:
myClass.string = #"test";
NSLog(#"appDelegate: %#", myClass.string);
I get this:
appDelegate: (null)
UPDATE2:
I wrote #class AppDelegate; underneath the #import lines in the viewController, but still I can't access myClass. A main problem, which may be the cause why this isn't working from the views, is that I can't even access myClass from AppDelegate.
In AppDelegate.h I wrote:
#property (strong, nonatomic) testClass *myClass;
In AppDelegate.m:
#import "testClass.h"
#synthesize myClass;
This should be right, right?
myClass.h
#property (strong, nonatomic) NSString *string;
myClass.m
#synthesize string;
When I then try to access myClass from appDelegate, I write:
self.myClass.string = #"test";
NSLog(#"appDelegate: %#", self.myClass.string);
The result is:
appDelegate: (null)
I think you have to allocate and initialize the myClass
Write myClass = [MyClass alloc] init] in AppDelegate.m file
#import "AppDelegate"
and also write
#class AppDelegate;
Unless you haven't shown it, you're not allocating testClass and not assigning it to myClass. Objective-C is not like C++ or Java where you can simply declare a variable of a particular class type and have it instantiated on the stack. Each class you use must be instantiated, whether manually or through InterfaceBuilder. The exception is there are some classes provided by the various frameworks which have a single shared instance. Rather than allocating those classes, you simply ask for the shared instance. However, that's not the case here. It's your own class, so you need to allocate it.
It would look like:
myClass = [[testClass alloc] init];

Does categories allow to use dot syntax when accessing chained methods?

I need to attach a method to all my UIViewControllers. The method just returns a pointer to my main app delegate class object. However, xcode 4 throws an error "parse issue expected a type" in header file at the declaration of output parameter type MyAppDelegate. If I change it to the other type, for example id, then the error goes away. But I'm using a dot syntax to access main app delegate properties and if I will change the type to id then xcode4 not recognize my main app delegate properties. I have included the definition file of category to those UIViewController class files where I'm accessing this method. Here is definition of my category:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
#interface UIViewController (MyCategory)
-(MyAppDelegate *) appDelegate; // xcode 4 complains about MyAppDelegate type, though it autocompletes it and show even in green color.
#end
Here is an implementation:
#import "MyCategory.h"
#implementation UIViewController (MyCategory)
-(MyAppDelegate *)appDelegate{
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
return delegate;
}
EDIT: The reason why I'm implementing this category is that I need to have handy shortcut for accessing my main app delegate from any place of the code (in my case from UIViewControler objects):
// handy shortcut :)
self.appDelegate.someMethod;
//not so handy shortcut :(
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
I think you have a dependency cycle in your header files. If MyAppDelegate.h imports MyCategory.h either directly or indirectly, the first time the category declaration is compiled the compiler won't know what a MyAppDelegate is. You should remove the import of MyAppDelegate.h from the MyCategory.h header and replace it with a forward class declaration:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#class MyAppDelegate
#interface UIViewController (MyCategory)
-(MyAppDelegate *) appDelegate;
#end
Then put the import in the .m file instead. This is actually a good general principle. Where possible, use forward class declarations in the headers and put imports in the implementation file.
-(id)appDelegate{
return [[UIApplication sharedApplication] delegate];
}
//Calling code
MyAppDelegate* delegate = (MyAppDelegate*)[self appDelegate];
Add #class MyAppDelegate; to the top of your category header to let the compiler know that this class exists or #import its header.
Generally, it might be a better idea to have a class method in MyAppDelegate that does the same thing. Conceptually, appDelegate is not a property of an individual view controller which your method implies.