Make label content persistent through the changes of storyboard scenes - objective-c

I have a storyboard with three scenes, all of which contain the same UILabel. It is connected to an IBOutlet, IBOutlet UILabel *mainLabel; in my ViewController.h and everything works until the scene is changed, when it resets as if the app was killed from the background and launched again.
The UILabel should simply not reset when the scene is changed and keep the value it had prior to the change instead of resetting to the default value.
The changes between scenes are done solely through the Storyboard as modal segues.
I would provide more relevant code but I can't find anything that could affect this.
How would You fix this?

is the viewDidUnload called?
in case of memory needs a view not on screen can be unloaded, in that case it gets loaded again from the nib the next time it is needed, restoring to default values.
the viewController is not, so you can store the label content in an ivar (NSString?) and on viewDidLoad you can restore then the state of your label.

Related

1 second delay when laoding UITableViewController with custom tableview cell

I have scene with UITableViewController designed in storyboard. The table uses custom made UITableViewCell - designed in .xib, .m and .h files. The background color of this cell is clear as well as the label and button inside it.
.xib file design:
real scene:
When I push from another scene, there is a delay nearly 1 second - between viewWillAppear and viewDidAppear of this UITableViewController. I can see this delay only on real device - not in the simulator.
The background of the whole scene is set in UITableView property of UITableViewController - it is an image 640x960px with size of 51kB.
Why is the push so slow? Is it because of the transparency or because of the combining storyboard and xib files? Or what is the proper design in such a situation when I want to have scene like this
EDIT:
I run some profiling in Instruments and I can see that there is a bunch of time spent for calling auto layout methods. I'm not very experienced with using Instruments, so what I did was - I run the app, and then I pushed couple times the problamatic controller. This is the result:
I just tried to remove the constraints for the custom table view cell but it has no effects. Any advice?

ViewDidLoad and UINavigationController in iOS?

I have an app which is based on a UINavigationController. There is a menu screen with buttons that segue (push onto navigation controller stack) to one of 9 other "sub-screens". None of these sub-screens segue to any other screen. When a user is done inputing data on a "sub-screen" they can press a done button which will pop back to the original menu screen. (If you're having difficulty picturing this, imagine a tree like storyboard where there is one root ViewController and then 9 leaf viewControllers).
Ok, so with that setup I have a few questions about how viewDidLoad works.
~ First, is viewDidLoad supposed to be called every time we transition to a sub-screen. For example, suppose I go from the menu screen to sub-screen "B", back to the menu screen and then back to sub-screen "B". Should B's viewDidLoad method be called twice? If not, why might mine be getting called twice?
~ Second, assuming that it will get called each time, what do I do if I have a lot of long operations that need to be performed exactly one time for each sub-screen? Where should I put them (if I put them in viewDidLoad it would happen multiple times if the user kept going back and forth between this page and the menu)?
To answer your questions:
Yes, in general B's viewDidLoad method should be called each time that it is pushed onto the UINavigationController's stack. This is because each time that B is popped off of the stack it is typically released, and each time that you go to B a new instance of B is created.
There could be numerous ways to handle this type of situation. It is hard to tell what is right for you without seeing exactly what you are trying to do. One way would be to create a singleton object that handles the processing. The reason this might be better than handling it within your UIViewController is that a singleton can live throughout the lifetime of the application, whereas UIViewControllers typically have a relatively short lifespan. Singleton objects can be created just once and they can manage whatever operations and data that you need to persist through the lifetime of your application.
1.
viewDidLoad is called when the view is loaded, and viewWillAppear is called when the view becomes visible.
If your viewDidLoad is called several times that means that you are loading the view every time you are showing it and releasing it every time you are popping it. If you post some code I could help you identify the problem better.
What you could do is something like this:
In your "root" viewController class, declare each "leaf" ViewController as a member, lets say they are called leafController1, leafController2 etc and create retain-properties for them.
#interface YourRootViewController : UIViewController {
LeafController1Class *leafController1;
LeafController2Class *leafController2;
// ...
}
#property (nonatomic, retain) LeafController1Class *leafController1;
#property (nonatomic, retain) LeafController2Class *leafController2;
// ...
#end
In the ViewDidLoad of your top ViewController, init all the leaf-controllers using "initWithNibName" etc (or whatever you are doing to create them). Retain their instances like so:
self.leafController1 = [[[LeafController1Class alloc] initWithNibName:#"LeafController1NibName" bundle:nil] autorelease];
When the user presses a button, push the correct leaf to the navigationcontroller:
[myNavigationController pushViewController:leafController1 animated:YES];
When you pop the leaf controllers now, they will be kept in memory since you retained them.
This way your viewDidLoad will only be called once for each leaf, just as long as you always push the same instace of the viewcontroller to your navigationcontroller.
2.
Heavy code related to the view should be executed when the view has been loaded, i.e. triggered by viewDidLoad. But also it might be a good idea to keep other classes that hold info about your application which are not viewcontrollers and separate from the UI. Heavy computations is better made in the background, or when the app is loading for the first time.
viewWillAppear gets called every time the view appears. viewDidLoad ONLY gets called when the view is constructed - so for example after a view controller initFromNibNamed call when the view is accessed. viewWillAppear is called anytime your view controller was not in view but comes into view - so when your view controller is pushed, viewWillAppear is called. So you might think your viewDidLoad is being called twice, but in reality it's probably not. So you should put the methods in viewDidLoad. What are you doing that takes a long time?

IBOutlet is somehow a NSZombie?

This is an OS X application. I am designing a custom sheet. Within my XIB file I have the sheet's window and a subclass of NSViewController which is responsible for controlling the views within the window/sheet. The owner of the XIB is another controller class.
I placed an NSTextField into the window's content view. In my NSViewController I created an IBOutlet declaration for the NSTextField and ensured the outlet was properly connected in the XIB.
I overrode -[NSViewController setRepresentedObject:] and within that method I am looking at the representedObject and depending on it's properties I am either removing the NSTextField from it's superview or I'm adding it back into the superview.
The first time I display my sheet with a representedObject that dictates the textfield should be removed from the superview. This works just fine.
The second time I display my sheet with a representedObject that dictates the textfield should be added back to the superview my application crashes with EXC_BAD_ACCESS when calling -[NSView addSubview:].
Running Instruments shows that the NSTextField was a Zombie at the time I tried to add it back to the superview. Instruments also indicates that every call to retain/release/autorelease was performed by either AppKit or Foundation - so at no point does any of my code increase or decrease the retain count. In fact the only two lines that reference the IBOutlet in my code are a call to -[NSView removeFromSuperview] and -[NSView addSubview:].
Am I doing something wrong or is this a bug in OS X? An IBOutlet should never be deallocated unless the XIB is unloaded.
Well naturally I figured it out like 2 minutes after I posted my question.
There are actually 2 textfields in my XIB both of which have identical behavior as described in the question. Only one of the textfields was turning into a NSZombie which made things more confusing.
Well when I was designing the XIB I laid down one NSTextField, configured it, and then copied it by holding Option while dragging the NSTextField. I did ensure the outlets were setup properly for the copied NSTextField, but for some reason the objects remained the same.
The solution was to delete the offending NSTextField and then drop a fresh one from the palette and configure it that way.

iOS Text View Not Updating

I've got a UITextView defined by
#property (nonatomic, retain) IBOutlet UITextView *quote;
in my view controller header, and I can set the value by using
quote.text = #"some text";
but the view doens't want to update the value, what can I do
Setting the text should immediately cause the UITextView to render your text under normal conditions.
Are you sure your that:
The UITextView is placed appropriately in your Nib and is visible?
The UITextView is appropriately linked with your outlet in your file owner (aka view controller)?
A quick test to verify the visibility of your UITextView - just place some sample text in it in the nib and verify that it appears on launch. If so, then you know that at least your view is displaying appropriately. At that point, it would have to be related to #2.
Make sure you connected quote to your UITextField in your XIB. Also, make sure that you #synthesize quote; in your .m.
I just bumped into this too and the problem went away as soon as I specified enough height for the content. In Xcode it may still look all right, but AutoLayout decided to do without the TextView if there was no height-constraint on it.
This was probably not your problem back when you asked the question, but it still turned up fairly early in my google search, therefore I post this answer anyway.
Btw: Xcode is still acting a little skiddish when you edit the constraint. It will update the view (and save) if you hit 'Enter' in the Constant-Field, but it will not do so if it loses focus in some other way.
This just to show us how difficult it is to get user interfaces right all the time.

uitextfield delegate must be file's owner?

I've seen a few references (eg here) in response to folks having trouble getting the keyboard to dismiss in iPhone that say "double check that the delegate is attached to file's owner.
Is this necessarily true? Or just standard practice? Can't I have other objects in my nib, such as a subclass of UIViewController, and make connections to those as I like? I'd hate to have to route everything into the object that happens to be file owner.
That said, I'm having a difficult time getting the keyboard to disappear. I know it's connected to the delegate, because I can set break points and step through the code. I can see the [theTextField resignFirstResponder] get called (and return true), but the keyboard still won't go away.
Any other suggestions?
All of the controls in a particular view are intended to talk to the View Controller that owns the nib file. Even if you have, say, a UISlider that changes the value of a UITextField, this will be handled by a method in your UIViewController subclass that gets fired when the slider's value changes and updates the text in the text field. So 9 times out of 10 your UIViewController will be the nib file's owner.
Typically the text field delegate method you want to define is textFieldShouldReturn, calling resignFirstResponder on the text field, which it sounds like you've done.
Make sure that your outlet for theTextField is connected as well. It can be nil and the runtime will treat [nil resignFirstResponder] as a noop, not as an error.