2

In my AppDelegate, I download some data from the internet and store it into an array. I want one of my ViewControllers to access that array. How would I go about in doing so? Is this a good situation to implement a delegate or a protocol? If so, can someone recommend a good tutorial for that?

Thank you

EDIT:

Please note that the data refreshes upon each launch so there is no need for Core Data or plists. Furthermore, the data are custom objects which I created so they can't be stored in a plist for example.

darksky
  • 20,411
  • 61
  • 165
  • 254
  • I think the answers depends on if the data is immutable and only loaded once on start up (PUSHED to the viewcontroller ONCE) or if the data is mutable and the interested view needs to be notified of changes (OBSERVABLE PUSH) or if the view controller needs to PULL data on demand from the data object. – JAL Aug 07 '11 at 19:41
  • is it really that complicated, i think we could read a lot into what the user is trying to achieve and the problems he is trying to solve, i just read this as he is trying to access data that he stores in his app delegate. Yes, the design choice is questionable but purely based on the question posed, its quite straightforwards. "How do i access data stored in my app delegate from anywhere in my app" – Matt Aug 07 '11 at 19:57

5 Answers5

3

You have 2 options:

  1. Implement a delegate protocol
  2. Use NSNotifications

The advantages/disadvantages of each is set out well in this question and answer: Delegates v Notifications

As notifications are easier to implement and may well be sufficient for your needs, you can implement it with the following steps:

  1. In the class where you download the data: When the data has been downloaded and the array populated, include the following lines:

NSDictionary *dict = [NSDictionary dictionaryWithObject:array forKey:@"Data"]; [[NSNotificationCenter defaultCenter] postNotificationName:@"DataDownloaded" object:self userInfo:dict];

  1. In the class where you want to receive the data:

2.1 Add the following line to your viewDidLoad method:

`[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataDownloaded:) name:@"DataDownloaded" object:nil];

2.2 Create the dataDownloaded selector:

  • (void)dataDownloaded:(NSNotification *)note {

    NSDictionary *dict = note.userInfo; NSArray *dataArray = [note.userInfo objectForKey:@"DataDownloaded"];

2.3 Add the following line to dealloc and viewDidUnload:

[[[NSNotificationCenter defaultCenter] removeObserver:self];
Community
  • 1
  • 1
RunLoop
  • 20,288
  • 21
  • 96
  • 151
  • i dont think this really answers the question though, the OP has not indicated that he has a problem knowing when data is available, but how to access it from elsewhere in his app. Personally i find notifications a bit coarse grained but tend to fit will with non-functional parts of an app, e.g. Reachability. some better code design would probably see the data encapsulated in a dedicated class available through a factory interface (maintaining testability) as a pseudo singleton. – Matt Aug 07 '11 at 19:31
0

You can store data in plist file and use it in all view controllers. This way, you need not worry about the size of data (as you will load it on demand and free it immediately).

Tatvamasi
  • 2,537
  • 19
  • 14
  • Problem is my data is not part of Foundation. It is a custom object that I created which plists can't store. Also, I do not need to use Core Data for that as the data refreshes upon each launch. – darksky Aug 07 '11 at 19:18
  • you can store in plist files or `archives` without using/knowing coredata. all you need to do is, make the data comply to NSCoding protocol. If that is not possible, i doubt there is any elegant way, than to maintain global data and deal with synchronization. – Tatvamasi Aug 07 '11 at 19:40
0

if you want to store your array in delegate then in any view you have to create reference of your delegate and you can access your array in that view like :

in your other view you have to write : in .h file

#import "YourDelegateFile.h" and declare a varialble

YourDelegateFile *appDelegate ;

in your .m file :

- (void) viewDidLoad
{
   appDelegate = (YourDelegateFile *)[UIApplication sharedApplication] delegate];

   NSArray *aArray = [appDelegate yourArrayName]; //yourArrayName is an array that you have declare in delegate 
}

hope it helps you.

Maulik
  • 19,348
  • 14
  • 82
  • 137
  • Is that considered good design though? I've heard several times that it is not recommended at all... – darksky Aug 07 '11 at 19:22
  • it does answer the original posters question though, although this code may not work depending on what the selector "yourArrayName" is – Matt Aug 07 '11 at 19:59
0

you just need to access the data stored within the appdelegate. I dont think this is the best solution to your problem but in order to do things the way you want.

so declare you property in your Appdelegate .h file

NSMutableArray* myArray_;

then add a property to the same file

@property (nonatomic, retain) NSMutableArray* myArray;

in the .m file

make sure you synthesize your property

@synthesize myArray = myArray_;

somewhere in your appdelegate .m file you will set the value

then, elsewhere in your code you can access the property in the appdelegate like so

MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
NSMutableArray* localArray = appDelegate.myArray;

Note, for good encapsulation you should really use an NSArray but i used mutable to keep the code short.

Also, using the appdelegate as a global store for program data is not a good idea, it breaks a lot of rules you shouldnt break, single responsibility principle being a good one to start with. You should ideally be storing application data in a dedicated class, perhaps a singleton or for much better testability a single instance class served by a factory class. This way you data is accessible from a known well defined entity, it is testable and it honours good design principles

Matt
  • 4,253
  • 1
  • 27
  • 29
  • In my case, would you just recommend a singleton class? Basically I have a list of 10 channels. For each channel I need to store three things: now, next and later. So something like two embedded NSDictionaries in a singleton class would do it? Please note I am also talking about good design. Good design is as important as functionality to me. – darksky Aug 07 '11 at 22:45
  • Singletons are controversial see this article http://www.ibm.com/developerworks/webservices/library/co-single/index.html they do have their place but they break a lot of good practices such as the single responsibility principle, is so much as they are responsible for the functionality they provide to your app as well as managing the fact that there is only one instance, they also make testing hard. There are some more elaborate ways of better engineering things using a factory to manage singleton-ness. A whole book could be dedicated to this subject, id recommend reading about it.. – Matt Aug 08 '11 at 08:42
  • personally it sounds like the only thing that differentiates now, next and later is the time at which you look at that data, although this makes assumptions on how you request the data and how it is returned. Why not model a channel as an object it is responsible for knowing its programmes and then have some operations for determining which is now, next or later, you may need a channelManager class which contains the channels objects you will also probably find that it helps to model a request as an object and build some code around that for making requests and processing responses. up to you – Matt Aug 08 '11 at 11:52
0

You can send notification if app delegate got new data and all interested controllers will know that they need to update views. For this you can use NSNotificationCenter. For example

- (void)newDataLoaded {
  NSDictionary *userInfo = [NSDictionary dictionaryWithObject:arrayOfData forKey:@"data"];
  [[NSNotificationCenter defaultCenter] postNotificationName:@"data updated notification name" object:nil userInfo:userInfo];
}

If some controller interested in data updates it should subscribe for this notification as soon as possible:

- (void)viewDidLoad {
  ...
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataUpdatedNotificationHandler:) name:@"data updated notification name" object:nil];
  ...
}

Do not forget to unsubscribe from notifications if you don't need it. For this use [[NSNotificationCenter defautCenter] removeObserver:self] in viewDidUnload and dealloc methods.

- (void)dataUpdatedNotificationHandler:(NSNotification*)notification {
  NSArray *data = [[notification userInfo] objectForKey:@"data"];
  // update your view here
}
Mikhail Grebionkin
  • 3,806
  • 2
  • 17
  • 18