How to define a global variable in a Cocoa Framework - objective-c

When you build a Cocoa App, you can add all the global methods and objects in AppDelegate class, and in any place of the code, you can get access to AppDelegate via
AppDelegate* appDlgt = (AppDelegate*)[[NSApplication sharedApplication] delegate];
But how can I do the same thing in a Cocoa Framework? It doesn't seem to have AppDelegete
Thanks

Like this
+ (instancetype)sharedMyClass
{
static id kSharedMyClass = nil;
static dispatch_once_t theOnceToken;
dispatch_once( &theOnceToken, ^{ kSharedMyClass = [[self alloc] init]; } );
return kSharedMyClass;
}

NSApp is the shortcut to your NSApplication instance, which normally have a delegate, or more archaically, a subclass where you could store data.
so if you followed the default project template:
((YourAppDelegate *)[NSApp delegate]).property
will get you where you want to go
don't abuse this, as you should only really store things that belong to the application in the delegate, and even then, those user defined properties should be NSUserDefaults or contained in some other controller class.
edit: sorry, I kind of missed the point....
if you need higher level application data to be passed down into a framework, then you can do so many things, with out knowing the specifics it would be hard to comment on which would be best...
some options:
define a protocol in the framework with the properties you are interested in, the adopt that protocol in your delegate.
then ((id <FrameworkProtocol>)NSApp.delegate).protoPropertywould work.
but that introduces a requirement that the delegate adopts that protocol, which you can check with the conformsToProtocol: method.

Related

How does the "managedObjectContext" method work?

I'm just beginning to learn how to use Core Data. The tutorial that I'm learning from feels very helpful so far. In the part where they hook up the view controller where we want to store data to core data, they didn't explain the process of the method that does this "magic".
It's an implementation of the method managedObjectContext, so I thought it could be helpful if I post it here and you can explain to me/us what is the process that is being done here:
- (NSManagedObjectContext *) managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
Also for some reason when I'm returning the context object it's not in regular colour when I'm returning a class object, its just white:
Thanks a bunch!
id delegate = [[UIApplication sharedApplication] delegate];
Here, we acquire a reference to the application delegate. This is an instance of the class that XCode generated for you (which should have the name [Prefix of your project]AppDelegate).
[UIApplication sharedApplication] returns a singleton object. Singleton is a design pattern which can basically be summed up as "if you call this method, it will always return the same object." So what that means here is that we are always getting the same application delegate whenever we call this in the program.
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
I'm actually kind of at a loss for why the tutorial wants you to call performSelector: here, respondsToSelector: seems a lot more appropriate, and performSelector: will raise an exception if your delegate object isn't of the right class anyway, so there's no point in guarding the actual message with an if statement.
If you ignore what seems to me to be unnecessary boilerplate, all you're doing is calling a method on the app delegate singleton. You can look it up in your project and see what it does -- judging by the context, it returns an NSManagedObjectContext class.
return context;
Note that this is not actually returning a class object, but instead a instance of NSManagedObjectContext. Therefore, the color white is to be expected.
What that code is doing is
Looking up the app delegate object. This is probably called something like AppDelegate in your project. This code finds the singleton by asking the shared UIApplication instance for its delegate.
Checking that the app delegate has a method named managedObjectContext.
If so, calling that method, and returning the result.
This is a lousy way to do it. Much better would be to declare a property on the view controller:
#property (readwrite, strong) NSManagedObjectContext *managedObjectContext;
Then assign a value to it when creating the view controller
newViewController.managedObjectContext = self.managedObjectContext;
That is, pass the managed object context around, assigning it to whatever object needs to use it. Don't assume that you can always look it up from the app delegate, because that will break if you ever change that part of your app delegate.
Xcode uses that color because it's a local variable in that method. Whether it's an object or some other type doesn't matter.

How do I have an instance available globally in Objective-C (iOS 6 app)?

Brand new to objective-C and iOS development (from a C background). I'm writing an app using the tab bar controller and using multiple views. I want to initialise an object when the app starts and then have that instance available to all the views.
Currently in my AppDelegate.m, I have:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
id myObject;
myObject = [[MYObject alloc] init];
return YES;
}
How do I access myObject for my other view controllers?
Thanks! (and excuse the newbie question)
As others have suggested, there are numerous options:
Singleton pattern:
+ (id)sharedFoo {
static dispatch_once_t pred;
static FooClass *cSharedInstance = nil;
dispatch_once(&pred, ^{ cSharedInstance = [[super alloc] init]; });
return cSharedInstance;
}
...and access the object [Foo sharedFoo] throughout. Some developers shun the singleton class because it risks creating not just a "god class", but something of a pantheon of such classes when the developer realizes that more and more objects need to become global. Often that impulse is related to incompletely thinking about the design of the application. A variation on the singleton idea uses a singleton to hold references to all global data, e.g. [MyApplicationData sharedData]... Personally, I consider it a little cleaner than using the UIApplication's delegate for this purpose.
Dependency injection:
Since you are using a UITabBarController design, you could use dependency injection (via UITabBarControllerDelegate methods such as tabBarController:didSelectViewController:) to propagate the object when the user selects a tab, then further propagate it down the controller hierarchy.
Application delegate as owner:
Like the singleton class, this risks creating a class with excessive responsibilities. No only is the UIApplication delegate responsible for application lifecycle, it becomes responsible for all sorts of other states and behaviors that aren't related. However, this pattern is widely used in code that I see.
There are lots of possibilities.
Just declare the object outside any class implementation, like in plain-old C. Or you could use a singleton class as storage for all your global data.
you might use singleton pattern:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32

Category on NSObject to get instance of AppDelegate?

I need access to my core data managed object context often, and instead of getting an instance of the [[UIApplication sharedApplication] delegate] and storing it in a variable every time in every class, I was wondering if it would be ok to do this:
#interface NSObject(DelegateExtension)
- (AppDelegate*)appDelegate;
#end
#implementation
NSObject(DelegateExtension)
- (AppDelegate*)appDelegate
{
return (AppDelegate*)[[UIApplication sharedApplication] delegate];
}
#end
so then I can just do self.appDelegate anywhere in my code.
Is anything wrong with doing this that might night be obvious? Is it bad programming practice?
Alternatively, you could add a preprocessor macro (or a static C function) to your Prefix.pch file:
#define AppDelegateInstance() (AppDelegate *)[[UIApplication sharedApplication] delegate]
This will make your app delegate accessible from anywhere in your code, and there is no chance of conflicting with any existing methods named appDelegate.
I usually use a global variable to point to the app delegate.
In MyAppDelegate.h:
extern MyAppDelegate* AppDelegate;
In MyAppDelegate.m:
MyAppDelegate* AppDelegate = nil;
- (id)init {
if (self = [super init]) {
AppDelegate = self;
…
}
}
Now anyone who imports "MyAppDelegate.h" can use the AppDelegate variable to access your app delegate.
NSObject doesn't have any meaningful connection to UIApplication or its delegate. From a design standpoint, I think doing this would be a hack in the bad sense. There are three other solutions that I can come up with off the top of my head that I think would be millions of times better:
Function, whose declaration is in a header which is imported by your prefix header.
Category on UIApplication, which is actually a class that has something to do with the action you're trying to take.
Global pointer, like NSApp on OS X*, that's set up as the first thing in your program to point to the UIApplication instance.
(Four solutions!) Global pointer to the app delegate.
See On lazy instantiation and convenience methods for info on implementing 3 or 4.
*Really don't understand why they didn't do this on iOS.
Of course it's safe, so long as you know that apple doesn't or won't have a method named appDelegate in the near future. Subclassing is the preferred method, especially because NSObject is a root class. But, that would require class posing, something deprecated completely in OSX 10.5+ and never even a viable option on iOS devices.

Where and how should I instantiate an object which will be used globally in an IOS app?

For simplicity's sake, lets say I am making a stopwatch application for ios5. I have a class called stopwatch, which represents the stopwatch's state. This class possesses members that store elapsed time, whether the stopwatch is running, etc.
To me, it seems this class should be instantiated once at the beginning of my apps lifetime, thus I declare it to be a member of the AppDelegate class and instantiate it in the didFinishLaunchingWithOptions: method of the AppDelegate class
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
Stopwatch *stopwatch = [[Stopwatch alloc] init];
return YES;
}
However, I now find myself needing to be able to reference this stopwatch object in the ViewController class but not knowing how to do so.
I would greatly appreciate any advice as to how to approach this problem, as it seems to be a fundamental concept for making ios applications. Thank you!
Don’t use a singleton. There are plenty of reasons why singletons are a bad design decision in most cases, I wrote a blog post about some of them.
Don’t store arbitrary data in the app delegate. That’s just misusing an existing singleton to do what you want. The app delegate should be concerned with the app’s lifecycle events, it should not be a place to stick whatever data you want accessible from everywhere.
One possible correct approach to solve this problem is to have a class that will create you application’s object graph for you and pass the instances to all interested classes. My app delegate’s application did finish launching method mostly look like this:
- (BOOL) applicationDidFinishWhatever
{
Factory *factory = [[Factory alloc] init];
[self setWindow:[factory buildMainWindow]];
[window makeKeyAndSomething];
return YES;
}
And all the object creation and assembly gets done in the Factory class. The Factory will create the timer (and keep the single instance in memory, if needed) and it will pass the timer to view controllers:
- (void) buildMainWindow
{
UIWindow *window = …;
[window setRootViewController:[self buildMainController]];
return window;
}
- (void) buildMainController
{
UIViewController *controller = …;
[controller setTimer:[self buildTimer]];
return controller;
}
I have created a sample Xcode project that shows how to wire an app without singletons. It’s very simple right now, I will add some common use cases later.
You can use Singleton pattern. look here for more info What should my Objective-C singleton look like?
If you "declare it to be a member of the AppDelegate class" then you should use it as a property:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
Stopwatch *aStopwatch = [[Stopwatch alloc] init];
self.stopwatch = aStopwatch;
[aStopwatch release];
...
}
Later, anywhere in your code:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate doSomethingWithStopwatchMethod];
someVariable = appDelegate.stopwatch.timeSinceStart;
...
Another approach would be to use a singleton (check SO for dozens of questions on the subject) or even a plain global variable (an integer holding a flag for instance) declared in main.m.

Trying to Access Application Delegate Variables / Properties

I am using a variable/propery of my application delegate as a global. (I don't want to deal with a singleton class.)
I am trying to write a #define statement in my Application Delegate class. If I type:
[UIApplication sharedApplication]
in my app delegate class, code hinting does not recognize sharedApplication. But if I type the same thing in a viewController class, "sharedApplication" pops right up.
In order to define a NSMutableDictionary in my applicationDelegate.h (or .m?), I write:
#define MyDictionary [[[UIApplication sharedApplication] delegate] stateDictionary]
Then if I try to use it in another class:
[[MyDictionary objectForKey:#"California"] largestCity];
I get an error that MyDictionary must be declared first. I am really confused about a lot of concepts here.
I'm pretty sure that someone will answer this better, but here's a quick one:
Let's say your application is called myApplication. Assign "global" property to MyApplicationDelegate, and then it will be accessible from anywhere like this:
// get reference to app delegate
MyApplicationDelegate *appDelegate = (MyApplicationDelegate *)[[UIApplication sharedApplication] delegate]
Property *myProperty = appDelegate.property;
Also, make sure that you link to MyApplicationDelegate file in header:
#import "MyApplicationDelegate.h"
There's a longer debate if using "global" objects is good design in general, but I won't go into that now.
I always add a category to UIApplication such as this:
#interface UIApplication (MyAppDelegate)
+(MyAppDelegate*)sharedMyAppDelegate;
#end
This way I do not have to worry about type casts at all. I often define and implement this category in the same file as the MyAppDelegate class itself. So this is the header I #import all over. All you can add it to your MyProject_Prefix.chp file.
Singletons are not bad, if your architecture is properly layered (And yes it is fully testable).