iOS sharing 'global data' across view controllers - ios

I have been using app delegate as a "global bucket" to share data between various view controllers. Typically I do something like this:
My_AppDelegate *appDelegate = (My_AppDelegate *)[[UIApplication sharedApplication] delegate];
And then, I would stick data into the appDelegate, and pick up data from the appDelegate with another view controller. Somehow, this seems clumsy and inappropriate (although it does work).
Is there a better way? Can I set-up a "listener" on some kind of a global sharing area, if somebody sticks a data element in there, another object would get a 'call-back' to let it know that somebody has data ready for it?
In Java we used to do this with Observer/Observable class - maybe there is something like this, or better in iOS?

A cleaner, although not necessarily different, way to do this is to create a singleton class, e.g. AppData, which you can access in a variety of ways, and which would be available to all your other classes. It has the benefit of separating your app-specific stuff from the app delegate stuff. You might define the class this way:
#interface AppData : NSObject
// Perhaps you'll declare some class methods here...
#end
A common thing I do is define class methods on such a class to access, for example, settings values, or app-specific constants or other singleton objects. There are a lot of possibilities.
In the end, you can get a lot done with just class methods, that you would call something like [AppData theMethod]. Just remember there's no self to access inside a class method.
Taking it one step further, you can define ivars for the AppData class, and then manage a singleton instance of AppData. Use a class method, e.g. +sharedInstance, to get a handle to the singleton on which you could then call mehods. For example, [[AppData sharedInstance] someMethod:myArgument]. Your implementation of +sharedInstance can be where you manage the actual creation of the singleton, which the method ultimately returns.
I am not sure if I'd call this approach a "best practice", but I've found this pattern quite handy.

Related

Relation between Singleton class & AppDelegate class in iOS Objective-C

I have a variable declared in AppDelegate class(.h file) whose value gets changed from multiple ViewController classes.Also,single application-wide instance for my AppDelegate class is shared throughout my application as follows :
AppDelegate *AppD = (AppDelegate *)[[UIApplication sharedApplication] delegate];
As I could access this variable declared in AppDelegate from any ViewController class, is AppDelegate class as an example of Singleton class in this scenario?
Can anyone help to site out the usage of singleton class with real-life example ?
AppDelegate is however a singleton class but you show only use it for declaring things that applies globally in your application.For ex: If you want to change the color of navigation bar in your entire application you can use app delegate and set the color of navigation bar. Also app delegate is an object that handles different state transition in your app. So if you want to create a variable that can be changed from multiple View controllers you should create a singleton class and declare that variable in that class.
The app delegate is not supposed to be a repository for all kinds of global variables. The app delegate is supposed to be used for things that affect the whole of the application, like launch / app termination, entering the background and returning from the background, that kind of thing.
If there is state that is shared by multiple view controllers, that should exist only once, but doesn't affect the application as a whole, then you could consider creating a singleton for that state. Then again, global state that is just an artefact of how you write your code should be avoided.
AppDelegate can be used just like singleton, but I don't recommend it. It's like you can put all your classes declarations and definitions in a class.h and a class.m file. Simply import the class.h file can invoke all classes. But it will be very inconvenient to read, understand and manage.
AppDelegate is mainly used for all kinds of app itself event, through UIApplicationDelegate method. Do not recommend deal with too much logic about global data here. Such as classes named XXManager, XXService, PublicData, is proposed to manage all kinds of singleton data.

Should I avoid a Singleton in this case?

I've been thinking about using a singleton on my data class in my current app. I've also been thinking of reasons not to use the pattern and currently I am stuck in the middle.
The reason I am for the singleton in this case is due to accessibility to methods and properties easily that I need to use more than once throughout the app. I could use the appDelegate for this but that muddles up the area of concern as these methods / variables have nothing to do with the app state - more to do with user input. The data will be persisted with eventually with NSUserDefaults - which is a singleton already.
The reason I am against it is because its another singleton to an app that already bass one (The appDelegate)
My question:
Would using another Singleton to access the data model be the correct way / acceptable way of doing it - or should I look at another approach?
I personally think there would be nothing wrong with a singleton as a data model - using the app delegate to instantiate it when the app starts and then access its various methods / properties when I need them throughout the app. This would be the only other singleton in the app (Maybe another one for user management - e.g.; logging in / out / profile / credentials, etc? )
Any thoughts?
Thanks all!
There is no problem having multiple singleton classes within ios, in fact in many of my projects most of the classes are singletons. Normally I have the data access logic and control within a singleton and then actual object classes as instances.
As you have already identified you really do not want to be putting something into AppDelegate that does not apply to the whole app.
From my point of view do not instanciate the class from AppDelegate, simply have the class instanciate itself on first access.
Whenever I am explaining singleton Objective-C to people I always direct them to this site, it may be worth a view for you:
http://www.galloway.me.uk/tutorials/singleton-classes/
It explains only what you need in a really easy to understand way. The bit that does the 'self-instanciating' is this bit:
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
You could use singleton in these case. Don't use delegate to hold values for your app. You may use same singleton for user management also.
Note : Don't use globals unless you need to do so. Singletons and top-level data should be used only when the data they contain truly belongs at the top level.

Casting of [UIApplication sharedApplication].delegate

I've got a test project to use the private data object on several view controller.
(I've downloaded it from web & git-hub)
- (ExampleAppDataObject*) theAppDataObject;
{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
ExampleAppDataObject* theDataObject;
theDataObject = (ExampleAppDataObject*) theDelegate.theAppDataObject;
return theDataObject;
}
First question is, theDelegate was casted with AppDelegateProtocol, even this applications UIApplication delegate name was ViewControllerDataSharingAppDelegate, and there's no warning. I can't under stand why, maybe it's because that was a id type?
(AppDelegateProtocol is a custom delegate protocol he declared in the AppDelegate.)
Second, it shows this kind of code on every view controller, and it seems like just a single-ton pattern.
I don't think this is not the best way to transfer data between view controller.
Which is the best way to transfer object data type?
Thanks.
Creating a protocol decouples the code somewhat from the specific implementation. You could conceivably have several applications, each of which uses its own custom class as an app delegate, but all implementations conform to the AppDelegateProtocol.
I used to use the app delegate to hold global data and methods a lot when I first started in iOS.
However, that fills your app delegate with app-specific code.
I've shifted away from that approach recently, and use a data container singleton (and perhaps a utility methods singleton as well.) As is typical for a singleton, I define a class method that lets me fetch the singleton. I add properties to my singleton as needed to store data, and then just use the class method to get a pointer to the singleton. I write my class method to lazy load the singleton.
Its also easy to make your data container singleton persistent by making it conform to NSCoding. Then every time you get moved to the background, just save your singleton somewhere. On app launch, read it in.

Move from old-fashioned struct to class

I know this could be a noob question but I am a bit stucked here. I usualy makes the following to access app data in different ViewControllers: First I declare a global.h module like this
global.h
typedef struct {
NSString *appName
NSString *appVersion;
bool mode;
} structApp;
extern structApp app;
After that I declare in MainViewController.h the struct so that I can access data
#implementation ViewController
structApp app;
- (void)viewDidLoad
{
app.appVersion = #"v1.02";
}
#end
And then I include "global.h" in every ViewController.h
This way I can access globally. As far I can see this is a good implementation and I have used it in more than 20 apps. Problem starts when this struct grows in size. In those cases I see corrupted memory, nil variables that were previously loaded with data, etc.
There is a better way of making data available in all ViewController? Please give me some examples if you can.
You have two options
Use a singleton class - Refer Objective C Singleton
Declare properties in App delegate - Refer SO
You can access the app delegate from any class using:
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
As you were using extern in your structure, any object updating the same value.
In OOPS, global variables are never said Good, so you need to use a singleton pattern.
Create a singleton/shared class having all those stuffs in your structure and use it.
You should deal with struct only if you deal with primitive data (if you are in a OOP way).
app.appVersion = #"v1.02";
Make your struct pointing on dangling pointer, since you are pointing a data in a function scope (app.appVersion is only holding the pointer, not the data). So you must retain all those object values in order to make it content safe, but i must admit it is still a Q&D approach.
If you need global access to data, you can use a singleton, only if you really need strong encapsulation and control to data.
How to make a singleton
What should my Objective-C singleton look like?
You can use macro too, that way you'll can use constants string without worrying data persistency, since they will always be available into the scope you are dealing with.
If you only want to read the data and you dont need any complex data structure you can also use a settings file like
Settings.h
#define appName #"blabla"
#define appVersion #"1.01"
#define mode 1
In General using struct should work fine. There is nothing wrong with using them. If you observe weird values caused by overlapping memory or illegal re-use of it or so then your problem is somewhere else but not in using structs in principle. The extern statement could lead to such an issue.
A class is not much more than a struct too, from a memory usage perspective. If I were you I would design a class with properties where ever you have members when using a struct. And make use of them in pretty the same way.
For "global variables" I apply a singleton pattern. That is basically a class with a class method (the leading + instead of -) that makes the one and only instance of the class available. Within that method I check if the class (a class internal static reference to the same class) is already available (!= nil) and instantiate it. Sometimes I use the initialize method for that. Initialize is an objective-c typical thing. It is called only once for each class, even subclassed ones, when or before the class is used for the first time. A very good place for instantiating class variables as singletons but not portable to other programming languages.

iOS: Adding class method to the application delegate?

Is ok if I add class methods that I need over all my project in the application delegate?
and then I import the delegate in the current UIViewController and I invoke the method: [MyAppDelegate classMethod];
Is a good approach ?
thanks
I set up an APP_DELEGATE macro that is defined as:
#define APP_DELEGATE ((AppDelegate *)[[UIApplication sharedApplication] delegate])
... so when I need to use it, I just code:
[APP_DELEGATE someInstanceMethod];
So yes, I use instance methods instead (for simplicity). Just define this macro in your AppDelegate.h and include it wherever you need it.
I think it should be fine, but I would only do it if it a) makes sense, and b) is truly the only place for that method. I'd think long and hard about whether that functionality belongs in the delegate or in some other singleton or shared class.
I would say that it's an acceptable approach but I would not recommend it. It depends on what the methods you are taking about do. For example, if you want to be able to access your data model from everywhere in your app, it's better to use a singleton, so that you separate the model completely from the rest of the app.
it's depending upon ur app needs or context.
if u r going to access class variables then u can choose class methods to create.
but u cannot access the instance variables.
but my choice is instance method which will operate on both class variable and instance variable.
The difference between class methods and instance methods are
Class methods
Operate on Class variables (they can not access instance variables)
Do not require an object to be instantiated to be applied
Sometimes can be a code smell (some people who are new to OOP use as a crutch to do Structured Programming in an OO enviroment)
Instance methods
Operate on instances variables and class variables
Must have an instanciated object to operate on

Resources