Been researching how to send data from one child view to another child view. The application has several views, where one is kind of real-time Settings view. Changes in settings should effect stuff inside other views.
NSUserDefaults seems to be popular, but I don't want persistent data nor automatic saving into database/file. Looks like potential slowdown, which I want to avoid.
Second popular thing is passing a reference to some common top level object into each child view. Just haven't found any tutorial, which would show me in detail how to do this... Most likely so easy, no tutorial is needed - after you figure it out once! Would appreciate, if you can point me to right direction (URL)!
Question: I'm thinking about using one "singleton object" to store "global data", access it from everywhere anytime. What could wrong with this? If I create it at e.g. appDelegate.m it should exist before anyone tries to access it, right?
I'm looking at this sample code.
I would recommend using delegates and/or notifications.
Instead of creating a new singleton in the app delegate, add the necessary data (or, even better, references to the data) in the app delegate and have the views have references to the app delegate.
You can also set up notifications so that your views can keep track of changes to the data that they display.
The beauty of a singleton is that it is automatically created when you first access it via some [singletonClass sharedInstance]. So you don't need to "create" it while launching. If it is global data that needs to be accessed from any view singleton might be the right way of doing this.
Related
I have a view that is to be shown from different screens in my app. I dont want to allocate and initialize the view from each screen. I thought this could be done using two approaches:
1) Initialize the view in App Delegate and access the same from all the screens. (Note: I dont want add the view on window because my app only supports landscape orientation and this will result in lot of spaghetti code to manage the view orientation.)
2) Make the view singleton instead
Now, there has been a lot debate on whether the Singleton pattern in general is good or bad. Also, I know that using singletons for view controllers is considered as bad idea .
Is there any better approach to achieve this??
Using singletons is not a bad idea, it's actually a solid pattern that allows storage of fast accessible data throughout the application lifecycle. NSUserDefaults, NSFileManager, NSNotificationCenter and many other Apple default classes use singleton pattern. If your view takes up too much memory (e.g. it has a lot of heavy graphical assets on it), then you should have a class that creates that view each time you call it and loads it into memory for a period of time that the view is used in. If your view is light weight, you should create it statically and keep it alive throughout the entire App's lifecycle using singleton class.
Using a singleton or using a property of your app delegate are equivalent ways of accomplishing the same thing. One can also use a common structure passed to all of the "interested parties".
Which you choose is up to you -- the "ideal" choice depends on the circumstances.
Do be wary, however, of ending up with dozens or hundreds of singletons -- this usually indicates that your design is not very well thought out.
Singletons are modern global variables so I try to avoid them unless absolutely necessary. The use of Apple's low memory globals caused all sorts of problems when porting to Carbon.
If you are maintaining libraries beware that there will be an instance of the singleton for each library so you need to be careful who is accessing them. I ran into this with the Loki singleton implementation (C++), although it would make sense that an Objective-C singleton would have the same issue.
I have a view that is to be shown from different screens in my app. I
dont want to allocate and initialize the view from each screen.
Why don't you want to create the view as you need it? Views use a lot of memory:
a half-screen view (240*320) on a non-retina iPhone requires 300KB just for the pixels.
the same view on a retina display requires 1.2MB
For that reason alone, allocating your common view only when you actually need it seems like a very good idea. There's nothing to be gained by hanging onto the view when it's not being displayed.
I'm far far down the road of having built all my nice buttons and things in a XIB, and I had the sudden realization that people will pay $200 more for the lower quality laptop "Cause it's pink!" but I digress.
I need to somehow centrally control the colour scheme of my app, and change colours on the fly. I have a couple ideas, like maybe a singleton "Theme" object with a few kvo compliant properties holding theme colours and fonts, then have the view controller "listen" for changes, and re-paint everything when the theme changes.
Problems with this so far: I'd need to have a pointer to every single UI object, including things like table view cells - which seems like a pain. Another possibility would be to subclass all my themed UI objects, maybe get them to register as observers on their own, but that makes me wonder about the overhead needed for this, maybe KVO isn't even the way to go here, I don't know.
So I'm wondering if anyone could share what they've done in the past, what works and what leads to big problems?
Thanks!
Update
I ended up going with a singleton object called SkinDispatcher, which only contains a lot of properties that are meant to be observed by UIView subclasses. Then I made quick and dirty subclasses of UILabel, UIButton, UITextField, anything else I happened to use.
These subclasses each looked up their tag number and used it to register for changes to the applicable fonts and colours, in awakeFromNib.
Next I made a class specifically for loading a style, which essentially opens up a plist file full of keys holding font names and R|G|B|A colours, reads them in and sets them to the applicable property in SkinDispatcher, as determined by key name. The last step (yet to be tried) is to set an observer on the StandardUserDefaults key for skins, props to the answerer for that idea.
You already mentioned a possible approach, namely using KVO. ANother possibility is to register for a specific notification, and react accordingly when the notification arrives in your view controller.
So right now when my app starts I get all of my data from Core Data. My data has entities of Groups and People. The Groups contain People. So as I go through the app I'm adding and deleting People and Groups.
My problem lies when I select a Group from a tableview and I pass that Group onto the next tableview. From that tableview I can press a button/row and add a bunch of People from a modal view. When I press Done from that modal view I need it to update the previous view with those new People, which it's not doing correctly.
It seems a little, for lack of a better word, wrong that I'm passing a lot of stuff around. Would it be better for me to use another fetch after I update People in a Group? From reading what other people say, then I could have different views listen for an updated Core Data and change their views accordingly.
I really hope this makes sense. I've been reading a lot to try to figure out the best approach but I'm not getting anything definite. I feel like my code is turning into spaghetti so I stopped and I'm trying to rethink it all. I'm also thinking maybe I need my very own Model class as opposed to just the classes that Core Data auto-generates.
From what you've written what you're doing sounds about right. I assume you're using a NSFetchedResultsController. Have you implemented the delegate methods outlined in the docs? Specifically, the controllerWillChangeContent: method should give you what you're after.
Regarding implementing your own NSManagedObject subclass, take a look at MOGenerator.
I would recommend NSFetchedResultsController to you. See documentation at ...
http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html
Look at CoreDataBooks example, especially at RootViewController.m at ...
http://developer.apple.com/library/ios/#samplecode/CoreDataBooks/Listings/Classes_RootViewController_m.html%23//apple_ref/doc/uid/DTS40008405-Classes_RootViewController_m-DontLinkElementID_14
NSFetchedResultsControllerDelegate can help you to update your previous view easily. As I wrote, look at sample code to see how it really works.
I've got a program which is working and uses Core Data for storage.
However, I'm not entirely sure if I should be keeping my fetch/update methods exclusively to the app delegate?
One example is for a question within the app. The question has a "left" and a "right" statement.
The delegate currently creates the new QuestionVC and passes in the questionNumber for the question. Then the QuestionVC then does a fetch to get the question object and uses the left and right properties of the object to set the text on the screen.
Should I do this the other way round...
The delegate does a fetch on the question number and then creates the QuestionVC and passes in the question object. The QuestionVC then just has to get the left and right text without having to do a fetch at all.
Any tips, advice welcome.
Thanks
Oliver
Both approaches sound valid, but if you can design your view controller hierarchy in such a way that only one object needs to know about Core Data (i.e. pass the question object to your QuestionVC) then that's probably a simpler design, which is probably better.
I personally wouldn't be doing any fetching in my app delegate, though. My app delegates only set up Core Data (i.e. the managed object context) and pass that to the root view controller. I prefer to keep my app delegates as small as possible. I don't use them as an all-purpose singleton.
I am learning tons on this thing. Reading also, but this is awesome!
Ok.. so long story sort I hope. I'm making a data class to pump out some instances of people that have various attributes. I would like my view controllers to be able to access them (through properties of course.. I think) to manipulate their data.
Where in an iphone app would be the best place to do this, and how would you write the code to message to this object. My current setup would be to have a navigation controller with a firstlevelviewcontroller that created a few secondlevelviewcontroller children instances that would do things like pickers for date of birth, and height, weight, etc.
Could the Navigation Controller make these model objects? Should application delegate? Lets say application delegate does. If so, then how would I put references to these objects from my first and second level view controllers?
Awesome!
**Update for the new millenium. **
I'm reading on core data structures, and though they are awesome, they are above and beyond what I need for this project. what I need is simple, I think..
I want one class that is a data class with a few variables that I can manipulate. I want to manipulate these from two view controllers. I might want more than one data instance, so I don't want a singleton data object. I don't need a persistent store of data.
I would like to know how to step by step have this data class instantiated.. should it be in app delegate? can i do it somewhere else? I dont want it a child of one of the view controllers.. How would I do that? then, how would I reference it from the view controllers and manipulate data (I'm pretty sure through properties but I can't figure out how to reference the instances to make this happen).
CHeers! thanks for the help!
Lots of questions that fringe on conjunction of various best practices.
First, the NSManagedObjectContext (if instantiated in the application delegate) can be shared in any number of ways. You can push it on through as you load your controllers or, something I've been more want to do (and will gladly argue the merits), you can hand it off to a Singleton that any controller has access to.
Depending on the model graph and how your UI maps to the data objects (you didn't say), keep in mind being memory friendly. I defer creating the NSFetchRequests until there is a controller that needs the data (CRUD).
If you want to edit your question or add comments that may provide more clarity... the answer may change
Frank