UIVIewController custom init method - iphone

I want to implement a custom initialization method for my UIViewController subclass to "replace" the initWithNibName method.
This is the code:
- (id) initWithMessage:(NSString *)message {
if ((self = [super initWithNibName:#"ToolTip" bundle:nil])) {
label.text = message;
}
return self;
}
The label is loaded from xib but at this point the reference to the label is nil (probably because the xib is not loaded yet?). Does anyone know a solution for that? Thanks

I know this is an old question, but the correct answer is to use the viewDidLoad method to do any additional setup after the view has loaded. The view is not loaded until it's needed, and may be unloaded when a memory warning is received. For that reason, a view controller's view should not be touched in an init method.

You should declare the label programmatically and initialize it within the init rather than do it from the nib.
This is how :
Assume UILabel *label is a class variable with #property and #synthesize defined for it.
- (id) initWithMessage:(NSString *)message {
if ((self = [super initWithNibName:#"ToolTip" bundle:nil])) {
label = [[UILabel alloc] init];
label.text = message;
[self.view addSubView:label];
}
return self;
}
Release the label in the "dealloc" method.
Hope this helps.

Related

Add Tapku calendar to app

I am trying to add the Tapku calendar to my app. I am using storyboards, I have added the Tapku library, imported the necessary files and add the TKCalendarMonthViewDelegate methods. I am adding the calendar to a UIView called calendarView. When I run the app the calendar doesn't appear, just the view with nothing inside it.
-(void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:NO animated:YES];
self.navigationItem.hidesBackButton = YES;
calendar = [[TKCalendarMonthView alloc] init];
calendar.delegate = self;
calendar.dataSource = self;
calendar.frame = CGRectMake(0, 0, calendar.frame.size.width, calendar.frame.size.height);
// Ensure this is the last "addSubview" because the calendar must be the top most view layer
[self.view addSubview:calendar];
[calendar reload];
// Do any additional setup after loading the view.
}
Can anyone help me please?
try by specifing frame points directly,like this
calendar.frame = CGRectMake(0, 0, 320,400);
If you're adding TKCalendarMonthView to your view controller using a Storyboard, then you should not also be initializing another instance of TKCalendarMonthView in your view controller's -viewDidLoad method.
In your Storyboard:
Add a TKCalendarMonthView to your view controller.
Set the size contraints.
Connect TKCalendarMonthView to the outlet (see below) in your view controller.
In your view controller:
Add an outlet for the TKCalendarMonthView.
#interface YourViewController () <TKCalendarMonthViewDataSource, TKCalendarMonthViewDelegate>
#property (weak, nonatomic) IBOutlet TKCalendarMonthView *calendarMonthView;
#end
In -viewDidLoad, connect TKCalendarMonthView's delegate and data source. Note, you can also do this in the Storyboard if you first add the IBOutlet annotate to the delegate and dataSource properties in TKCalendarMonthView.h
#implementation YourViewController
...
- (void)viewDidLoad
{
[super viewDidLoad];
...
self.calendarMonthView.delegate = self;
self.calendarMonthView.dataSource = self;
However these changes alone will not get the TKCalendarMonthView to display the calendar. The reason is that the view is getting initialized by the Storyboard but none of the existing -init methods are called when loaded by the Storyboard. So you will need to add an -initWithCoder: method to TKCalendarMonthView.m. The following example will call the default -init: method.
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [self init];
if (self) {
}
return self;
}
If you do all this, you should see the rendered calendar instead of a blank view.

Setting Property upon Initialization

I am creating an instance of a view controller and then presenting it modally on another view as such:
[viewController receiveNumber1:number1 andNumber2:number2];
[viewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:viewController animated:YES];
What I would like to do is set two properties within this new view controller upon initialization.
I can do this by calling a custom method like (somethings are int variables here):
[viewController methodProperty1:something1 andProperty2:something2];
However, I really need to set those properties right upon initialization because the content of the new view is dependent on those numbers.
Is there a way to pass on information to a new view while it is being initialized? Something like:
[[UIViewController alloc] initWithValue1:something1 andValue2:something2];
Also, I do not understand why
CustomViewController *view = [[CustomViewController alloc] init];
view.property = newValue; / [view setProperty:newValue];
does not work in this configuration, meaning the properties' values do not change. I can call methods within the new view and set its properties that way but not set the properties directly?
I'm sorry if these are lame questions, but I am sort of a beginner.
Thanks a bunch!
view.property = newValue and [view setProperty:newValue] are equivalent terminology.
You can implement one or multiple custom initialization methods for your view controller there is nothing that should stop from doing so. Have a look to the official doc to make sure you respect a couple of rules of how you should implement your custom initializer.
Your code snippet:
-(id)initWithValue1:(NSInteger)value1 andValue2:(NSInteger)value2
{
if (self = [super init])
{
_firstValue = value1;
_secondValue = value2;
return self;
}
else return nil; // or handle the error
}
In your CustomViewController.h, define two properties you want set and an initialization method, for example:
#property (nonatomic, assign) NSInteger firstValue;
#property (nonatomic, assign) NSInteger secondValue;
-(id)initWithFirstValue:(NSInteger)value1 andSecondValue:(NSInteger)value2;
Then, in your CustomViewController.m, implement the method you have declared earlier:
-(id)initWithFirstValue:(NSInteger)value1 andSecondValue:(NSInteger)value2
{
self = [super init];
if (self)
{
// Supposing you haven't synthesized your property and you are using
// latest Xcode build, instance variable are automatically created
_firstValue = value1;
_secondValue = value2;
}
return self;
}
Finally, you can allocate your controller using this line of code:
CustomViewController *controller = [[CustomViewController alloc] initWithFirstValue:value1ToSet andSecondValue:value2ToSet];
Some final advice
When you implement your custom initialization method, you should properly choose which init has to be called on super.
For instance, I prefer calling self = [super initWithFrame:CGRectZero]; if my controller is a subclass of UIViewController, or self = [super initWithStyle:UITableViewStylePlain]; if it is a subclass of UITableViewController.
There are other custom init method but you can find other information reading documentation about your custom controller superclass.

setting the value of a UILabel dynamically

i'm trying to build a quiz that sets the value of a UILabel dynamically through code.
i've done this successfully before, but for some reason it's not working this time. i suspect it's because the structure of this app is different. i've tried different fixes but haven't been able to get it to work.
the way my app is set up, i have a view controller with a view that has a segmented control. when you press one of the switches on the segmented control, it inserts a subview like this:
menuTable.hidden = YES;
additionPracticeController *additionPractice = [[additionPracticeController alloc]
initWithNibName:#"additionPractice"
bundle:nil];
self.addPracticeController = additionPractice;
[self.view insertSubview:additionPractice.view atIndex:0];
[additionPractice release];
the view controller for that subview displays its view like this:
- (void)viewWillAppear:(BOOL)animated{
firstNumberString = [NSString stringWithFormat:#"%d",arc4random() % 10];
firstNumberLabel.text = firstNumberString;
secondNumberLabel.text = secondNumberString;
[super viewWillAppear:animated]}
my outlets are connected and i can get the values to appear by setting them statically from the nib (even though that's not what i want). i've tried to set firstNumberString equal to all sorts of values, but nothing shows up when i set the values through code.
i'd really appreciate it if someone could help me solve this problem.
It sounds like you have the label connected in Interface Builder. I would need to see more code to know exactly what you are doing wrong. Make sure you are using a property for your label. The below code is a simple example of how this works.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UILabel *_displayMessage;
}
#property (nonatomic, retain) UILabel *displayMessage;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize displayMessage = _displayMessage;
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayMessage.text = #"Text Changed!";
}
- (void)viewDidUnload
{
self.displayMessage = nil;
[super viewDidUnload];
}
- (void)dealloc
{
[_displayMessage release];
[super dealloc];
}
#end
Instead of making your class a subclass of UIControl just implement this method below. When the user hits done or return the keypad will resign
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
To make the text field dismiss when the user taps outside of the text field.
Place this in ViewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
Place this method within the class:
-(void)dismissKeyboard
{
[aTextField resignFirstResponder];
}
Also if you want to dismiss the text field from another button spefically and not just a screen tap. Then just call this from within the button.
[your_textfield_name resignFirstResponder];

Why does myArray not get initialized?

- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
self = [super initWithStyle:style];
if (self) {
myArray = [[NSMutableArray alloc]init];
NSLog(#"ARRAY INITIALIZED"); //THIS NEVER OCCURS
}
return self;
}
Are you creating your table programmatically or is it in Interface Builder? If it's in interface builder, then you need to override -(id) initWithCoder:(NSCoder *)coder instead.
I would recommend just putting your initialization code in viewDidLoad or viewDidAppear. You would need to make sure you don't alloc multiple times (and orphan memory in the process), but it would get called regardless of whether this is rigged up in the xib or programmatically.
- (void)viewDidLoad
{
if(!myArray)
{
myArray = [[NSMutableArray alloc] init];
}
}
I can't really tell from your given code, but if you're making your controller programmatically, make sure you're initializing your subclass:
[[MyCustomTableViewController alloc] initWithStyle:style];
Rather than UITableViewController:
[[UITableViewController alloc] initWithStyle:style];
Found out that initWithStyle never gets called. I forgot to mention, the initial window is build in IB, so my custom controllers are called from the xib, and i have to override initWithCoder....
http://www.iosdeveloperforums.com/thread-initwithstyle-overriding

iPhone dev - viewDidLoad and viewDidUnload in programmatically created view?

I read somewhere that in a programmatically created view in a UIViewController, not using Interface Builder, -viewDidLoad and -viewDidUnload should not be used. Is this right? Why? Where would I release subviews that I have retaining properties of? Or should I just not use properties for them?
EDIT: Read my comments on Rob Napier's answer.
Create your subviews in -viewDidLoad. If you need ivars for them then only assign their values. The reference is hold by adding the views as subviews to you main view.
Then when your view is unloaded you should set your ivars to nil, because the object have been released since your view was removed and released.
So in your header
#interface MyViewController : UIViewController {
IBOutlet UIView *someSubview; // assigned
}
#property (nonatomic, assign) IBOutlet UIView someSubview;
#end
And in your implementation
#implementation MyViewController
//... some important stuff
- (void)viewDidLoad;
{
[super viewDidLoad];
someSubview = [[UIView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:someSubview]; // retains someSubview
[someSubview release]; // we don't hold it
}
- (void)viewDidUnload;
{
[super viewDidUnload];
someSubview = nil; // set the pointer to nil because someSubview has been released
}
//... more important stuff
#end
If you wish you can also not release someSubview in -viewDidLoad, but then you have to release it in -viewDidUnload AND -dealloc since (if I remember right) -viewDidUnload isn't called before -dealloc. But this isn't necessary if you don't retain someSubview.
the strange thing here is that an UIViewController not loaded from a NIB file is not notified about its view unloading (and so its viewDidUnload method is not called) unless you offer a base implementation of the loadView method, such as:
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease];
[self.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
}
- (void)viewDidLoad {
[super viewDidLoad];
// create views...
}
- (void)viewDidUnload {
// destroy views...
[super viewDidUnload];
}
this only happens to base UIViewController, an UITableViewController for example don't need to be fixed with this workaroud.
So Robs is right.