When can you set Interface Builder objects' properties? - iphone

When in the view life cycle can you change the values of objects that were put there in IB?
I have a stepper and a UIImageView that I put into the view in IB. I had put some values of them (like the stepper min and the UIImageView's image) in ViewDidLoad but when the view appears, it uses the stepper min and the image that were set in IB.

You can set the properties where you are trying.
Make sure to call [super viewDidLoad]
- (void)viewDidLoad
{
[super viewDidLoad];
// adjust views here
}
It is possible you forgot to connect your IBOutlets in IB:
This will lead to a bug that the compiler does not care about. Essentially your slider code would be equivalent to
[nil setMinimumValue:newVal];
I can run the following code in a test program and no complaints or crashes happen
UIStepper * step = nil;
step.minimumValue = 5;

You can set those values in viewDidLoad. It would be helpful if you posted your viewDidLoad source code.
Since I haven't seen your code, I can only guess at what is wrong. I suspect that your view controller has a property referencing the stepper and another property referencing the image view, and you are setting the values using those properties, like this:
- (void)viewDidLoad {
[super viewDidLoad];
self.stepper.minimumValue = minValueForStepper();
self.imageView.image = imageForImageView();
}
If your code has that basic structure and it's not working, you probably forgot to hook up those properties in your nib.

I dont understand you question very well, but if you want set your IBOutlets you can do programmatically for example, if you have a:
IBOutlet imageView *theImageView;
You can set one of UIImageView properties like that:
[theImageView setImage:[UIImage imageNamed:#"theimage.png"]];
You can study all the classes that you are interested in the Organizer view of Xcode, here you can view all of its properties, methods, delegate methods and so on.

Ah. I see the problem. I had a UILabel that was displaying the value and I didn't have it set yet to connect to the UIStepper's value until the value changed. My bad. Thanks guys!

Related

iOS - Presenting a UIViewController inside anther UIViewController

I dont have a very good understanding on the topic, so please bear with me
I am trying to display a UIViewController inside another UIViewController. I feel like there aren't enough examples out there. I have read the documentation but being fairly new to iOS I am kind of lost.
Here is my problem: I can get the child UIViewController to appear inside the parent UIViewController but the child view is not displaying right.
Sorry, I cant post pictures yet.
Here is my child - UIViewController.
Here is my parent - UIViewController. (The blue area is where the child view is added)
Here are the results:
Blue UIView in place - http://i.imgur.com/4vny8EZ.png
If i move the blue UIView over to the right here is what happens
Blue UiView moved over to the right - http://i.imgur.com/XCOBwr6.png
I have tried a lot of different things but my lack of knowledge on the subject is really making it difficult to find out what is wrong.
Here is how I am loading my child UiViewController in my parent UIViewControllers class:
- (void)viewDidLoad
{
[super viewDidLoad];
// Add Calculations View Controller
CalculationViewController *calculationController = [self.storyboard instantiateViewControllerWithIdentifier:#"Calculate"];
[self addChildViewController:calculationController];
calculationController.view.frame = self.calcualtionView.bounds;
[self.calcualtionView addSubview:calculationController.view];
}
So, my question is why is it displaying the child view in a weird fashion?
Thank you!
Also, sorry about the links I could only post two.
Quick answer: Views sizes aren't determined until viewWillAppear. Set the frame there and it will work.
Longer answer:
1) If you are using iOS6, I would encourage you to use NSLayoutConstraints to deal with view size and positioning rather than manually setting view frames. It takes a bit to really wrap your head around constaints, but once you do they are much more powerful and flexible than setting frames and you won't have to worry about when or how your IBOutlets are created
2) You are not adding your child view controller correctly. You must call didMoveToParentViewController: after the view is added. With the missing line of code as well as using contraints rather than frames your code looks like this:
CalculationViewController *calculationController =
[self.storyboard instantiateViewControllerWithIdentifier:#"Calculate"];
calculationController.translatesAutoresizingMaskIntoConstraints = NO;
[self addChildViewController:calculationController];
[self.calcualtionView addSubview:calculationController.view];
[calculationViewController didMoveToParentViewController:self];
// Add constraints for the view to fill calculationView
UIView *calcView = calculationController.view;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(calcView);
NSArray *hConstraint =
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[calcView]|"
options:0 metrics:nil
views:viewsDictionary];
[self.calculationView addConstraints:hConstraint];
NSArray *vConstraint =
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[calcView]|"
options:0 metrics:nil
views:viewsDictionary];
[self.calculationView addConstraints:vConstraint];
Move the code to viewDidAppear. If calculationView is an IBOutlet to a view, its bounds will be zero in viewDidLoad. The frames of views are not set until viewDidAppear.

UIBarButtonItem - Invalid tap glow size

I have a strange problem with glow that appears when pressing on a UIBarButtonItem in the UIToolbar control. When I set ImageInsets property to 4,0,0,0 the glow gets smaller every time I tap on it. Here is an illustration:
The problem doesn't appear if I don't set imageInsets. The problem appears for all buttons in the UIToolbar. I don't have tap handlers. Making bigger inset (e.g. 8,0,0,0) produces the same result faster.
I appreciate any suggestions on how to solve the problem.
EDIT: Changed the code to Objective-C since the problem reproduces without MonoTouch as well.
It's default single view project. I added a toolbar and a UIBarButtonItem into it using storyboard designer. Created an outlet for the button.
#import "ViewController.h"
#implementation ViewController
#synthesize testBtn;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 0, 0, 0);
[testBtn setImageInsets:insets];
}
- (void)viewDidUnload
{
[self setTestBtn:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
It is hard to see what the problem is without code. Would you mind posting the relevant parts of your code up? I am thinking it has something to do with you repeatedly incrementing the top inset by 4... I will edit my answer once I see the relevant code.
EDIT: So I am not familiar with Monotouch... and from the code you pasted I am assuming the constructor does indeed get called once. I am thinking there may be a bug in the Monotouch framework which is causing the imageinsets to be shifted by the specified amount (down 4) every time the button is tapped. I would check in the following order:
That the delegate method tied to the button is not pointing to the constructor.
Change the inset to (8,0,0,0) and in 5 taps do you see the same image as above (10x). If so it may be an issue with the monotouch framework or with how you hooked up your delegate method.
Sorry but I am unfamiliar with monotouch so I can't provide much more assistance. Unless you are locked into using Monotouch, I would strongly recommend you learn native Objective-C and program natively to avoid small pitfalls and headaches such as this. Objective-C and the iOS SDK is pretty elegant.
Finally, I asked designer to adjust image size and thus get rid of the imageSize property use.

My objects in storyboard don't link correctly with the code

I am trying to use storyboards in my application. I began well, I have added two view controllers with a button to go from the first to the second.
The problem is in this second view controller: the objects I add on it and link with the code do not work. When I set a breakpoint in the view controller code, the 'self.property' is set to nil, whereas it should be instantiated by the storyboard.
I have been looking for an answer for hours, and I really don't understand the problem, since all the rest seems to be good.
I have tried to write the property in the code (strong/nonatomic, nonatomic/retain and even weak/nonatomic), to link the object directly to the code so that it creates the property automatically, but I never get anything else than "nil" with breakpoints.
viewController.h:
#interface NMLoadingViewController : UIViewController
{
__weak IBOutlet UIProgressView *imageProcessingProgressView;
}
#property (weak, nonatomic) IBOutlet UIProgressView *imageProcessingProgressView;
#end
.m:
#synthesize imageProcessingProgressView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Custom initialization
NSLog(#"INIT.");
}
(amont other lines of irrelevant code)
If I set the breakpoint to the "INIT." line, my imageProcessingProgressView is nil. I can't see a reason for that, I guess I have missed a very little detail...
(Note that I have tried this with other objects, like a UILabel, but it did not work either. Stranger, when I had two objects, one of them had an adress which was not nil, but still it was corrupted and did not show the right object.)
Edit: It was a lot of trouble for nothing... The problem is about the Variable View in XCode, which show my variable to "nil", whereas a log shows me a correct object...
Remove this...
{
__weak IBOutlet UIProgressView *imageProcessingProgressView;
}
...and make the property strong.
Change your log message to...
NSLog(#"INIT: %#", self.imageProcessingProgressView);
...and see if you still have a problem. If you do, then take another look at your storyboard connections.
Make sure NMLoadingViewController is the class on your viewController
First try out the answer by #Eric because I do believe that is the real issue.
Also, make sure that you are actually using the interface builder to hook the controls back to the view controller. This is done by dragging a line from the control back to the property of the view controller.

Overwriting UINavigationBar to set a default titleView

What I want to do is a navigation bar with a image on it. I have a tab controller on my main view, and inside each tab I have a UINavigationController. From inside the UIViewController that my tab/navigationController calls, I could set the titleView without much problem, doing this inside the viewDidLoad method:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
But, I want to replace all titles in my navigationBar for this view, and it seems ugly to repeat this everywhere. So I did this on the delegate (after linking all the Outlet stuff)
self.tabOneNavController.navigationBar.topItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
Again, it worked! ok, I'm almost getting there.
But the point is, I've 5 tabs and all of them have navigationControllers inside. I reduced the code repetition from every internal view to only 5 times, but it still. It requires that I do that for the NavController of each tab.
Then I tried to extend the UINavigationBar to create my own, where I could set this in the initializer, and use it in the interface builder as the object class. But it doesn't seem to work. Here is what I did:
#implementation MyNavigationBar
- (id)init {
self = [super self];
self.tintColor = [UIColor greenColor];
self.topItem.title = #"testing please work";
return self;
}
#end
in the interface file MyNavigationBar inherits from UINavigationBar. But this didn't work. Should I overwrite other method? which one? is this a good practice?
I'm not even sure if I should add one navigationBar for each tab, as I said, I have tabs and I want to have a navigation bar / navigate inside them. By now, after a near death experience trying to figure out how the interface builder / outlets and classes work, the code is working, I just would like to make unglify it.
Thank you!
The problem of repeating code which you describe has an elegant solution. Objective-C supports something called a "category", which allows you to add methods to a class. A common use for this is to customize navigation and tab bars. In Xcode 4, you would do something like this to add a category on UINavigationBar:
Hit Command+N or open the "New File" dialog. Next, choose "Objective-C category" from the Cocoa Touch menu:
Click Next and you will be prompted to enter the name of the class that you would like to add methods to as a category. It should look something like this:
Then, you should end up with a save file dialog. A quick note about convention here. Convention is to name a category after the original class, the plus sign, and then a description of what you're adding. Here's what yours might look like:
Once you save your file, you will need get something like this:
Look at that beauty. You can now override the default drawing/init methods as well as extend the functionality of the navbar.
I'd suggest looking into the init and drawRect methods, although I don't remember which ones people use. Also, please note that while under NDA, this may change in iOS 5, so just be prepared for that possibility.
Why not define a UIViewController subclass which sets the title view via self.navigationItem.titleView and have your other view controllers extend from that class? Then you're sharing that behavior across all of your controllers without repeating the implementation.

How to update or reset a UIView with a custom subview?

I have a UIView in a UIViewController to which I add a custom subview in the viewDidAppear method.
MyView *myView = [[MyView alloc] initWithLabelText:text];
[self.view addSubview:myView];
[myView release];
The text variable is a string used on a label in myView. This text changes every time you come back to the current view. But it seems that viewDidAppear does not reload the view - it rather loads a new view over the old one - so I have two labels over each other.
I tried to use viewWillAppear but it doesn't make any difference. I also tried to use [self.view setNeedsDisplay] - doesn't help. I also tried to make myView an instance variable, but it also didn't help.
What worked was to remove the view explicitly, when I declared it as an instance variable:
- (void)viewDidDisappear:(BOOL)animated
{
[_myView removeFromSuperview];
}
Although there is this workaround I would like to simply reset the view when getting back to it. Does anybody know how to do that? I would appreciate it ;)
Don't alloc and init the custom subview every time, only the first time viewDidAppear is called. Then retain it in a property for subsequent use.
The followings thing can ben considered.
viewDidLoad --> alloc and init your sub views
viewDidAppear --> update sub views
dealloc --> release sub views.