Yes, I'm a noob at Xcode. right now I'm working my way through the Big Nerd Ranch IOS programming book, and I just need a little clarification on the Model-View-Controller bit.
Model class is called 'CellData', an NSObject
View class 'CellView', a UIView
Controller class is called 'CellAppDelegate', a UIResponder.
The DrawRect method does a lot of drawing, with colors based upon the data from the CellData Class. Everything so far seems tells me that I should not call a 'CellData' method from my 'CellView' class. Normally yeah when your just using UIButtons with TestFields, yeah, makes perfect sense.
In this case, I have up to pass a value from 'CellData' to 'CellView' up to 6000 times to refresh a View. Does it still make sense to keep on calling back and forth between using the CellAppDelegate (seems like a lot more work for the computer), or am I really 'allowed' to retrieve a value from CellData?
You've answered your question yourself really. No, 6000 calls per render isn't the right thing to do, especially on a table view cell which will be redrawn pretty frequently.
Personally, I see the controller's job as asking for data objects from the model layer (where business logic etc happens) and passing them into views. So, in your case, I would just pass the data object into your cell. (I would have it as a property on your cell with a setter that also called [self setNeedsDisplay]; to trigger a redraw)
That being said, I also tend to favour the model layer giving out immutable data objects so the controller / view can't do anything wrong with them :) With this approach, if the controller wanted to edit the data object it would have to call a method in the model layer to do so.
Though, of course, this is just my personal opinion and choice of architecture. And obviously for existing UI objects (i.e. a UILabel etc) I can't pass in the data object, I have to set the text property directly from my view controller.
PS CellAppDelegate is a bad name for a view controller - the custom is to end the class name with ViewController so it would be CellAppViewController. This naming scheme makes it very easy to come back to your code in a week or so and still understand what everything does :)
Everything so far seems tells me that I should not call a 'CellData' method from my 'CellView' class.
This sounds like a misunderstanding. It is extremely common for something like CellView to be handed a single CellData by the controller. The view is free to query the model object it is responsible for displaying. This is not a violation of MVC. It should generally not write to the model object, nor should it talk to other model objects typically.
Related
I have spent hours trying to use a set a tableViewCell from a picker selection in another view. I have posted two questions, that brought no answers. So i decided to approach it differently. I tired making a global variable, but then figured out, I had to make a dataClass file which wouldn't work for me because I have to use a viewController. Im beginning to lose hope. Is their any way to set the title of a table view cell from another view? Im not looking for a giant chunk of code, just a place to start. The way to actually do it, if its possible. Thanks in advance.
Yes, this is definitely possible. In Model-View-Controller systems all information sharing happens through your model class. Make it a singleton object (singleton is similar to global variables, but it has proper initialization).
Create a class with the data that must be shared. Create a class method of that class to produce the sole instance of that class. Define and initialize a static variable holding that instance. Use dispatch_once to initialize that instance. Here is an answer illustrating this approach.
With a singleton instance in place, all your view controllers can access the model as necessary. One view controller can set properties of the model, so that when the other view controller comes along, the data is ready for it to process.
I'm new to Objective-C and the iPhone and thought I was getting the hang of it until, after many play apps, I ran into a really basic problem around MVCs, NIBs and IB. Are there any really clear explained examples of how to follow this framework that I could go back to?
#interface test1ViewController : UIViewController {
IBOutlet myView *myview;
IBOutlet myModel *mymodel;
}
Both the views and models are linked in by IBOutlets but instantiating the model object either kills the application or produces an object which does not respond to any messages.
I am also unclear as to where to carry best out initialisations. I currently do this over viewDidLoad in the view controller. Is there a standard way to do this and does the simulator actually always start up in the same way? Should one use awakeFromNib? Does it make any difference if I use plain code or the IB? And if I have use the IB, should it include a model object?
The MVC idea would make good sense for me here because I have potentially several views and view controllers all feeding back into - and sharing - one common central data model. Any references or advance on this newbie problem would be more than welcome!
I wouldn't spend too much time worrying about the 'classic' definition of MVC. iOS follows it, but there's a lot of confusing terminology. ("View Controller")
You say trying to use model kills your app. Are you retaining myModel? You have to retain all IBOutlets.
nibs are collections of "Freeze-Dried" objects. When you load a nib, the objects in it are "rehydrated", if you will. This means they spring back to life with all of their properties set to whatever they were when you froze them. So you talk of "instantiating" and "initializing" but this does not apply to IB. The objects are ALREADY instantiated and initialized. Imagine that compiling the nib 'pauses' the objects. When you load the nib, the objects resume doing whatever they were doing when frozen. They will get an awakeFromNib message, so that's a good place to put some code to check on what the state of the app is, see if you have to do stuff with your object to bring it up to speed.
viewDidLoad seems like an "initialization" method but don't be fooled. It's part of the view controller life cycle and it can be called more than once! (If your controller's view is purged as part of a low memory warning, viewDidLoad might be called again if the view has to be... wait for it... reloaded.) So, it's appropriate to put view setup stuff in viewDidLoad, but not other initialization type things.
For the "common data" thing, I like to create a singleton data model class. Your various views can set properties on the model, or send notifications. You can also use KVO (key value observing) to watch for changes in the model.
IB makes functionality invisible. I don't like it and I don't use IB any more, preferring to have everything in code. Then when you look at code you see what is going on - all the navigation controllers, all the formatters etc. - without switching over to IB. Maybe Xcode4 will make it better with integrated IB but I probably won't go back. Lots of people do like IB so try both methods and see what you like best.
IBOutlet/IBAction actually mean nothing to the compiler but they let IB recognise the ivars it can send messages to or that will write to elements in a xib. Your use of it here is a bit simplistic unless you really do have a model that only communicates one way with the xib. What you more usually have is a range of controls in the xib linked to the view object, the view communicating directly with the controller. The controller communicates with the model. Very loosely speaking, model is your internal representation of data and logic, view is what you see, controller is the glue between them.
The MVC line can be fuzzy and you just have to get comfortable with it. If you have a slider control with a value representing some value in your model then it can be hard to think of it as part of the interface especially when you persist the value and use it as a central part of your model. I like the Stanford iPhone class introduction of it. They don't spend a heap of time on it because it can be difficult to follow exactly and there are situations where it isn't best.
Notes from that class - you can find the video on iTunes to follow along.
Your use of viewDidLoad is correct, that's your chance to perform initialization on views and their objects. If using IB you will probably not have much to do there because you can set most properties in the xib. If not using IB you will use it a lot more.
A lot of times something like your model would be wired at runtime by your application delegate or by the view controller itself.
IB is generally used more to link views and controllers together, with the application handing around model(s).
That said, you should be able to have IB create an instance of your model and assign it in an IBOutlet. Was your model OK with just being created without the classic init method being called? Did it implement NSCoding properly?
I have been using Objective-C for a while and pretty much understand most of its features. However, the concept of delegates eludes me. Can someone please give a succinct and easy to comprehend explanation of what delegates are, how they are used in the iPhone SDK, and how I can best make use of them in my own code?
Thank you!
There are a couple main reasons to use delegates in Objective-C, which are subtly different:
Enhancing the base functionality of a framework class. For example, a UITableView is pretty boring on its own, so you can give it a delegate to handle the interesting bits (creating table cells, adding text to section headers, what have you). This way, UITableView never changes, but different table views can look and act very differently.
Communicating to parent objects in your dependency hierarchy. For example, you may have a view with a button that the user may push to do something that affects other views. The view will have to send a message to its parent view, or perhaps the view controller, so that it can create or destroy or modify other views. To do this you'd pass the parent object into your view, most likely through a protocol, as a weak reference (in Objective-C, an assign property). The view could then send any message declared in the protocol to the parent, or delegate, object.
This approach need not involve views. For example NSURLConnection passes event back to its delegate, which may be the object that created it, using this mechanism.
Essentially, all a delegate is, is an object that accepts feedback from another object. Put simply, when stuff happens to an object, it tells its delegate (assuming it has one).
For instance, lets say I have a UIViewController with a UITextView placed in the middle of the view. I set up my UIViewController to be the delegate of the UITextView. Then, when certain actions are performed on the text view (begin editing, text changes, end editing, etc), it tells it's delegate so it can do whatever logic it needs to do, like spell checking every time characters change, or dismissing the keyboard when it receives a return key press.
Delegate methods perform a similar function to callback functions in C.
Hope that makes sense :)
Best and simple concept I got from a Lynda.com Tutorial was: When you set a Delegate it means you have been given work to do. So, if you want to use methods that are written in a protocol method, you must implement them by searching in the Delegate Class Reference and using them. I hope it helped.
By the way, Delegates are excellents. They are your friends. They have been made to make your life as a programmer much easier.
Having worked through some tutorials on some basics via the iPhone, I'm struggling to determine how best to structure my code. The book I'm using points out things like "you wouldn't normally put this here, but for expediency...". Well, I'd like to know what one would "normally" do.
My application is somewhat simple - there is a table view showing a list of objects and one can add, remove, edit these objects (I plan to provide a more sophisticated organizational scheme later, but I'm keeping it simple to get something working).
So, I have a RootViewController that extends UITableViewController. When the "add" button is clicked I push a subclass of UIViewController onto the stack (this class is the "add/edit" form for my objects). I have a simple data structure-style class to hold the fields of the objects.
The apps like this in the book basically put an array inside the RootViewController and use a reference to the model class to represent the "object being edited". Basically, the models are all wrapped up in the view controllers. This seems wrong.
So, my question is: where do the models and the objects for managing them normally live?
And, does the answer to this depend on how I'm storing my objects? I have not done much with CoreData, though my plan was to use it for persistence of my objects. Will the hooks and boilerplate provided by XCode make this a nonissue?
Best answers will be pointers to some best practices type stuff, which I wasn't able to easily find via Google or on Apple's Dev site.
First of all you are right about your intuition that it seems wrong. As you described the model is stored in the view controllers. That is a bad idea. By doing so you are violating the model-view-controller paradigm, which makes your code hard to maintain.
So what you need to do now is get your model in a separate object or tree of objects or even better use CoreData, which is also great in terms of memory management.
As you want to use CoreData you should have a look at the UIFetchedResultsController class which you will use to obtain the objects from the managedObjectContext which will be your model.
What you would do in your table view - detail edit example is:
Fetch the contents of the table view using a fetch request and setting it on the NSFetchedResultsController you hold as an instance variable in the rootViewController
Set this rootViewController as the delegate of that NSFetchedResultsController
If an item is checked or the add button is pressed push your detail view controller on the stack, pass the object to be edited with it, or nil if it is a new object. Also pass the managedObjectContext to the detailViewController. Update or create the object.
Implement the delegate methods of NSFetchedResultsController in your rootViewController and there you reload the contents of the table when necessary.
What you gain is a nice and clear separation of model (CoreData's managedObjectContext) the controller (rootViewController and detailViewController) and you views. If you now edit an entry by using the detail view, your rootViewController is notified via your NSFetchedResultsController and automatically updated. What you also gain is that you do not have a strong reference among the viewControllers in your application.
Btw, you set up your CoreData stuff in the application's delegate. There is a lot of boilerplate code around in Xcode and on the ADC. Check out the Recipies app [1] in which this approach I just descriped is used. There are also some videos about CoreData on Apple's developers site.
[1]: http://developer.apple.com/iphone/library/samplecode/iPhoneCoreDataRecipes/Introduction/Intro.html CoreDataRecipies
So I'm trying to use a UITableViewController (let's call it homeView) in my iPhone application to display a simple table with only a few rows of text which are loaded from an NSArray in the controller. I want to display the table in the grouped style in a subview of a subview (let's call it subSubView) of my main controller. When I try the following: [subSubView addSubview:homeView.view], my app crashes on launch. However, when I allocate the object without adding it to any views, it launches fine.
What's the best way (or rather a working way) to display the table generated by my UITableViewController?
There isn't enough to tell for sure what is going on, but if I had to guess I would think that you probably aren't retaining homeView. Normally I would say that as a comment to your question, since it is not really an answer, but I have a completely separate answer:
Just use a UITableView, not a UITableViewController. Instead of trying to embed a controller within a controller (which is quite difficult since Apple doesn't expose the necessary tools to actually modify the view controller hierarchy), just make the VC you are writing support the appropriate delegate/dataSource methods and directly create the view.
While it might make some logical sense to try to embed VCs inside of each other, with the exception of the builtin container VCs (UINavigationController, UITabBarController) it Really Doesn't Workâ˘. The technical reason for this is that internally some of the event routing and messaging depends on parentViewController being correct, but since you can't set it (setParentViewController: is private) tons of latent bugs in UIKit start rearing their head. The internal collection classes can set the parentViewController correctly, so everything works right.
Also, one last thing. In your question you named your view controller homeView. Please, please on't do that. A view controller and a view are separate things, call it homeViewController. Aside from the fact that a lot of new iPhone developers get confused about what the distinction is, there is nothing more aggravating then tracing through someone else's code and realizing that something you are assuming is one type is another.