Change UIView Dynamically - objective-c

Working on cs193p (stanford online videos of iphone programming), I am working on Presence1 exercise
I am trying to change a UIView which is a subview of another view dynamically.
For those of you who are not aware of the assignment posted on the course, Basically the architecture of the app is as follows:
Nav Controller -> (Root) View Controller - (VC)1 for 1st screen -> calls Detail View controller VC2 for next screen
Now 1st screen has images and text that I want to load dynamically from my model (which is an object I instantiate in App delegate before pushing the 1st VC on navigation stack. I have defined a parameter in initWithNibName method to pass this model object while initializing the nib for VC1. And I also try to set the image from the model over here and in viewDidLoad and viewDidAppear methods. Its not working.
When I debugged, I saw that the model object being passed is empty.
If you understand the problem, please lemme know what am I missing.
I can post the code if required but will have to post the whole thing to make any sense.

Nailed - I was releasing my model object when not required - I was creating a "reference" to one of my objects present in the model (array containing a list of objects) . Note - I was not creating a new object by using alloc/copy. I was then releasing it (even though after the push on to the navigation stack) - Obviously causing my object memory space to get cleared and that reflected in my view controller that was receiving that model object as a parameter in its init method. This was giving the illusion that the object is not getting passed to the view controller!
Lesson Learned earlier - Be very mindful about releasing objects.
Lesson Learned Today - Be very cautious when releasing objects. Don't over release objects - make sure you are releasing an object only if you are calling alloc/copy or retaining it explicitly - memory management 101 - revisited :)
Thanks all for not replying to this question. In a way it forced me to scrutinize my code at a very micro level and I am sure I wont forget this for rest of my life! :)

Related

iOS: Create copy of UINavigationController

It is possible, to create an exact object copy of a UINavigationController? I have seen examples of copying objects using copyWithZone:, but I am confused as to how I would use this to copy my UINavigationController.
Any help?
UINavigationController doesn't conform to the NSCopying protocol, so you can't use copyWithZone: or copy on it.
If you are looking to have a customised UINavigationController that you can use throughout the app then you should subclass it and then create a new instance of that subclass every time you need a new one, such as when you create a new modal view controller.
EDIT: If you want to keep the view controllers from a previous navigation controller then you can do something like this (use subclassed navigation controller if needed):
UINavigationController *newNavigationController = [[UINavigationController alloc] init];
[newNavigationController setViewControllers:oldNavigationController.viewControllers animated:NO];
This will do a shallow copy of the viewControllers, i.e. you will have references to the original navigation controller's view controllers, not copies. If you want to do a deep copy on the view controllers then that will be far more complicated and will require specific copying code for each view controller. (See here for more info).
You can do this by creating a category (or a subclass), make the category NSCoding compliant, and add the necessary encoding and decoding functions. You then need to determine what properties you want to encode - the types of view controllers it currently has in its array, and perhaps you'll need to make those objects be NSCoding compliant. You can see that this is not going to be a trivial thing to do, but its not impossible. You may find the solution to your problem is best done using some other techniques.
EDIT: If you want to "duplicate" it, what you really need to know is what viewControllers are in the array. So suppose you want to replicate "state", which in some sense is the same as the original answer but less rigorous. Add a category or method to each object and ask to to give you current state as a dictionary. For the navigationController, that might be just the classes of the objects currently on the stack.
For each of these objects on the stack, you get them to give you a dictionary of their state. By state, its means what text is in UITextFields, views etc, anything that that object would need to go from a startup condition and get back to where it is now.
You package this all up - the nav dictionary and array of the state ones. You can save this as a plist. When you want to construct where you were later, the nav controller can tell what objects to create by knowing their class, then as each one is created it can be sent its dictionary and told "get back to where you were". Once done, then push another controller on the stack.

Stanford iTunes U CS193P Assignment 3, Communication between two ViewControllers

Ok, I know that the model for the new graphing vc is going to be a subclass of the calculator brain, but how do I get the program stack of the CalculatorBrain from the old VC to the GraphingBrain of my new VC? DO I have to go down the stack on the Storyboard-segue?
I have the pinching and panning on the new axes setup, as well as the delegate to communicate between the new graph brain and graph vc. But isn't my programStack that the user typed in before "trapped" in the old MVC?
I think I've got the concept down, but I don't see the way for that communication to occur.
Thanks in advance!
***For those who don't follow the course, I have two MVCs linked by the NavigationController. The user enters a series of numbers and operations (in the first MVC) which are stored in are then stored in an array in the model of the first MVC. When a button is pressed, it segues to a new MVC, which needs the array that was entered in the previous MVC. How do I transfer that array between two seemingly separate MVCs? I don't think I can have a property in the second VC and set it from the first VC because it(the second MVC) is not instantiated yet. It maybe something with preparteToSegue but I'm not sure.
Having gone through CS193P (well more than half way there), I think I understand your questions. Here is what you need to remember:
To send a property value down the MVC (C --> V) path and in this case the V holds another MVC; use PrepareForSegue. Regardless of whether the destination has been instantiated or not, you need to do a few things:
Import, in the .h or .m file header of the 1st class, the 2nd class.
In the prepareForSegue, create an instance of the 2nd class and set it to be equal to segue.destinationViewController. You will need to typecast the latter to the second class.
Now you can set the property of this instance you created (of the 2nd class) to any value you want.
You cannot set any IBoutlet values for the second class, from the prepareForSegue, because IBOutlets are not setup until after ViewDidLoad.
For some odd reason, if you do use a condition to check for the segue.identifier, you will need to enclose the statements in {} even if it is only one statement.
Hope this helps and gets the juice flowing...
KMB

iOS ARC with when two objects need a pointer to the same thing

I'm going through my code to make sure that all of my properties have the proper weak/strong modifier and I ran across this situation which I don't know what to do with. Keep in mind that I'm fairly new to iOS programming.
I have a normal MVC hierarchy where my controller creates an object called FieldManager. This FieldManager is used by my controller to dynamically create textfields. However, this FieldManager also needs to be used by the controller's model to periodically query the manager to find out information about the fields (such as is it required, should it's text be capitalized...etc).
So to summarize, I have a controller which creates an object that is used both by the controller and the controller's model. Therefore, I don't know if I should make the model's reference to FieldManager a weak property or the controller's reference to it a weak property. It seems that I should make both weak properties, otherwise FieldManager will get released. What should I do?
Thanks.
Things like that should belong to your model, so the way to go is to have a datasource.
Your controller asks the datasource to create and return the textfields, the datasource contacts the model and asks for a field manager for that model.
That's the way I would do it...

Memory warning creating new object of root view controller

In my project, I am having an outlet for navigation controller. This works perfectly in general, but whenever my app receives memory warning, it creates a new object of root view controller class, that is assigned to the navigation controller through interface builder. After this event, two objects of root view controller resides in the memory and events gets fired twice. This is creating a mess in my case. Can you please suggest me a solution to this problem?
release the member variables, in viewDidUnload method which is called whenever the memory warning occurs. dealloc is not called so u need to release in viewDidUnload.
hope this helps.. happy coding :)

Traversing the ViewController hierarchy properly?

I'm having trouble referencing one view controller from another. The code works but I get warnings which makes me think I'm going about it wrong. I'm trying to reload the data in a tableView whose controller is in a NavigationController.
What's wrong with a message like this:
From the AppDelegate:
[self.tabBarController.selectedViewController.topViewController.tableView reloadData];
Although this works, I get the warning request for member 'topViewController' in something not a structure or union because Xcode doesn't know that the selectedViewController will return a navigationController. So I could do the following:
UINavigationController *myNavigationController = self.tabBarController.selectedViewController;
[myNavigationController.topViewController.tableView reloadData];
But then I get this warning: incompatible Objective-C types initializing 'struct UIViewController *', expected 'struct UINavigationController *'
How far do I have to go with this? The first line works. To get to the "right way" is it gonna take 8 lines of code?
A major code smell here, IMO. You're trying to do action at a (great) distance. It's not exactly clear what you're trying to accomplish, nor why you need to do this action from the app delegate. I have seen some developers treat the app delegate like a giant catch-all global lump of mud, and I think this is an anti-pattern that should be eliminated from iOS development.
Back to your question: you're trying to force a table view controller, inside a tab view controller, to reload its data. I'm assuming this is in response to something happening. Why not have the view controller in charge of that table watching for that event instead of the app delegate? That way, the thing that owns the table view is directly controlling it -- which is the entire point of the MVC pattern. This is a much better approach than having the app delegate drill down through a hierarchy to find a table view... in terms of complexity, readability, and brittleness.
If, for some reason, you can't or won't have that view controller observing for the event directly (hard to fathom why offhand), you could always have the app delegate post an NSNotification and let the view controller in charge of the table register as an observer for it. Not as good as direct observation, but definitely better than your current approach.
You can't use dot-notation unless the compiler knows what type of object you are using it on, and that that object type can receive a message with that name.
You can use dot-notation with a bunch of type-casts (which in this case, is hideously ugly):
[((UITableViewController *) ((UINavigationController *) self.tabBarController.selectedViewController).topViewController).tableView reloadData];
Or you can break it up into discrete steps:
UINavigationController *navController = (UINavigationController *) self.tabBarController.selectedViewController;
UITableViewController *tableViewController = (UITableViewController *) navController.topViewController;
[tableViewController.tableView reloadData];
Note that I'm assuming that your top VC is a sub-class of UITableViewController.
You really shouldn't be accessing the .tableView property externally - you should encapsulate that behaviour with a reloadData method on the View Controller itself. Even if all it does is call reloadData on its .tableView, you should encapsulate it. This will make your code more modular (which makes it easier to understand for you and others), and make it easier to expand on and add complexity to your View Controller down the track.
Without knowing exactly how this app is structured, I would guess that you're probably better off using notifications or observers to get your VC to reload its data. If you have some global event that requires a UI refresh, an NSNotification is a good way to make the UI layer get the message while keeping your code nice and modular.