Cocoa/Objective-C noob here.
I'm working on a simple app to learn some more about iOS development, and am struggling to see how my subclass of UITextView has it's viewDidLoad method called.
I am subclassing UITextView to CMTextView.
Using storyboard, I have a CMTextView in the window.
In CMTextView.m, I have the following:
#import "CMTextView.h"
#interface UITextView ()
- (id)styleString;
#end
#implementation CMTextView
- (id)styleString {
return [[super styleString] stringByAppendingString:#"; line-height: 1.1em"];
}
- (void)viewDidLoad {
NSLog(#"LOADED!"); // not doing anything...
}
I'm not doing anything fancy to add this as a subview of my window, but I thought the storyboard did that for me?
Does anyone have any advice?
The above answers are correct if you manually initialize the UITextView. If loading them from a nib, you need to override the -awakeFromNib method.
-(void)awakeFromNib
{
[super awakeFromNib]; // Don't forget to call super
//Do more intitialization here
}
If you want to handle the resizing also override the -layoutSubviews method
viewDidLoad is a method in UIViewController not UIView/UITextView
if you want to do any initialize then put it in initWithFrame:
viewDidLoad is a UIViewController method (see here).
UIKit ensures that viewDidLoad is called at appropriate times when you instantiate a view controller's view, but it has no role to play in a UIView like UITextView.
Usually, you prepare your view at initWithFrame time.
A view can never have the method viewDidLoad.
Some methods are tethered only to the viewcontroller and viewDidLoad is one of them.
The method constructors for views would be
-(id)init;
-(id)initWithFrame;
Related
I have two view Controllers in my project ViewController, SettingsView. Here I am trying to update the ViewController's label, when i click on the SettingsView's back button. NSLog is working fine, but the label is not updating...
Please help me....
SettingsView.m
-(IBAction)backToMain:(id) sender {
//calling update function from ViewController
ViewController * vc = [[ViewController alloc]init];
[vc updateLabel];
[vc release];
//close the SettingsView
[self dismissModalViewControllerAnimated:YES];
}
ViewController.m
- (void)updateLabel
{
NSLog(#"Iam inside updateLabel");
self.myLabel.text = #"test";
}
Could you please tell me whats wrong with my code? Thank you!
You have to implement protocols for that. Follow this:
1) In SettingView.h define protocol like this
#protocol ViewControllerDelegate
-(void) updateLabel;
#end
2) Define property in .h class and synthesis in .m class..
#property (nonatomic, retain) id <ViewControllerDelegate> viewControllerDelegate;
3) In SettingsView.m IBAction
-(IBAction)backToMain:(id) sender
{
[viewControllerDelegate updateLabel];
}
4) In ViewController.h adopt protocol like this
#interface ViewController<ViewControllerDelegate>
5) In viewController.m include this line in viewDidLoad
settingView.viewControllerDelegate=self
Your label is not updating because , you are trying to call updateLabel method with a new instance.
You should call updateLabel of the original instance of viewcontroller from which you have presented your modal view.
you can use a delegate mechansim or NSNotification to do the same.
Delegate mechnaism would be clean. NSNotification is quick and dirty.
You are not exactly calling the correct vc. This is because you are creating a new instance of that class and calling the updateLabel of that instance.
You have a few options.
Either implement it as a delegate callBack (delegate messagePassing, or delegate notification - however you want to call it) to notify that class instance to call the updateLabel method.
Use the original instance VC as a dependency injection into the class that you are on right now, and use that instance to call the updateLabel
Use NSNotifications / NSUserDefaults to communicate between viewControllers and setup a notification system for your actions. This is quite easy, but not really great in the long run.
I would RECOMMEND option 1 (or) option 2.
Simply declare like this in SettingsView class:
UILabel *lblInSettings;// and synthesize it
Now assign like below when you presenting Settings viewController:
settingsVC.lblInSettings=self.myLabel;
Then whatever you update in lblInSettings it will be present in MainView obviously....
no need for any delegate methods or updating methods.
Means if you assign at the time of dismissing like
lblInSettings.text=#"My new value";
then self.myLabel also will be updated.
Let me know if you have any queries?
I need to push a UIView into my UINavigation controller. I am doing it by
[self.view addSubview:showContactFlow];
And on a button click in UIView I need to push another UIViewController over the UIView. From the UIView I am not able to access self.navigationcontroller How can I do this?
Edit:
I have set the UIView as the view of a new UIViewController I am pushing into, the before mentioned UIViewController . Now I would like to know, how to handle the UIView button event inside its UIViewController, in which's view it is set.
Add a UINavigationController ivar to the UIView and assign it to the main view controller's. Then you should be able to access it from the UIView.
Edit:
Your UIView subclass:
// CustomView.h
#interface CustomView: UIView {
// ...
// your variables
// ...
UINavigationController *navController;
}
#property (nonatomic, assign) UINavigationController *navController; // assign, because this class is not the owner of the controller
// custom methods
#end
// CustomView.m
#implementation Customview
// synthesize other properties
#synthesize navController;
// implementation of custom methods
// don't release the navigation controller in the dealloc method, your class doesn't own it
#end
Then before the [self.view addSubview:showContactFlow]; line just add [showContactFlow setNavController:[self navigationController]]; and then you should be able to access your hierarchy's navigation controller from your UIView and use it to push other UIViewControllers.
You should try to work with an MVC approach. So your controller has access to all that stuff and can keep pushing and popping views, so the view doesn't need to know too much about the controller.
Otherwise, and for this case you can solve it fast by using delegation. So:
showContactFlow.delegate = self;
[self.view addSubview:showContactFlow];
So later in the UIView, you can just say:
[self.delegate addSubview:self];
This is gonna work, but it's not likely to be the best approach you should use.
On button click, you can present a view controller like,
-(void)buttonFunction{
ThirdVC *third= [[ThirdVC alloc]initWithNibNme];......
[self presentViewController:third animated:NO];
}
Using Core animation you can make NavigationController's pushviewController like animation on writing code in ThirdVC's viewWillAppear: method.
where do you add the UIButton is it in showContactFlow view or in the ViewController's view??
In regard to the modalViewControllers issue the correct method is
[self presentModalViewController:viewController animated:YES];
the standard animation in upwards
I have found quite a lot on this subject but I just can't figure it out. Any help would be massively appreciated!
I have an app set up with a UITabBarController. Within one of the tabs, I am showing a UITableView which is using a UINavigationController to allow for hierarchy. All the tables rotate just fine when the orientation is changed, until I get to what is effectively the final view in the hierarchy.
The final view is not a UITableView, just a basic UIView. But I can not get this page to rotate successfully! I have remade the view from with the absolute basics required and it still doesn't want to work! The code is below but it is currently pretty much a standard template with nothing in it now.
Also, I am not using InterfaceBuilder, and shouldAutorotateToInterfaceOrientation is on all views. This is the only one I am having problems with.
SomeView.h
#import <UIKit/UIKit.h>
#interface SomeView : UIViewController
{
NSString *someID;
NSString *someName;
}
#property(nonatomic,retain) NSString *someID;
#property(nonatomic,retain) NSString *someName;
#end
SomeView.m
#import "SomeView.h"
#import "AppDelegate.h"
#implementation SomeView
#synthesize someID, someName;
-(void)loadView
{
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidUnload
{
[super viewDidUnload];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)dealloc
{
[super dealloc];
}
#end
UPDATE 10th Nov 2011
I'm still having this issue, however looking through documents and bits this seems to be my problem (http://developer.apple.com/library/ios/#qa/qa1688/_index.html)
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
You may find a situation where shouldAutorotateToInterfaceOrientation is called once at startup for a given view controller but is never called again when the device is rotated. Because view controllers are tightly bound to the views they manage, they are also part of the responder chain used to handle events. View controllers are themselves descendants of the UIResponder class and are inserted into the responder chain between the managed view and its superview. So it is common practice to have one primary view controller in your application as part of the responder chain. You would typically add one primary view controller such as a UINavigationController, UITabBarController or a generic UIViewController to your UIWindow. For example, this is done by calling:
[myWindow addSubview:primaryViewController.view];
If you add an additional view controller's UIView property to UIWindow (at the same level as your primary view controller) via the following:
[myWindow addSubview:anotherController.view];
this additional view controller will not receive rotation events and will never rotate. Only the first view controller added to UIWindow will rotate.
My UITabBarController stopped to autorotate, when I added a new navigationController to it with a tableViewController and didn't notice, that my custom navigation controller's shouldAutorotateToInterfaceOrientation returns YES only for one orientation. The solution is to check shouldAutorotateToInterfaceOrientation function in each Controller inside TabBarController.
May be it will help to somebody.
And I have figured it out...
I was looking at the code which pushes the UIViewController onto the stack and I had not fully initied the UIViewController.
HI
How can I detect when I return to a view? I have an iPad app in development and I want to do something upon returning to a certain view. How can I do this?
Thanks.
Override the -viewWillAppear: or -viewDidAppear: method in the UIViewController subclass that manages the view. For example:
#implementation MyController
- (void)viewDidAppear:(BOOL)animated
{
// Do whatever you like here, for example...
[self setSomeBOOL:YES];
// Call super (per Apple's documentation).
[super viewDidAppear:animated];
}
#end
If you're using UITabBarController you can take a look at UITabBarControllerDelegate protocol:
– tabBarController:didSelectViewController:
If you're using UINavigationController then the corresponding delegate protocol is UINavigationControllerDelegate and the method:
– navigationController:didShowViewController:animated:
I have a custom UIview which is created programmatically. How to associate to it a custom UIViewController (programmatically as well)
Thanks and regards,
Implement loadView in the UIViewController to create a view hierarchy programmatically without a nib file.
- (void)loadView {
// allocate the subclassed UIView, and set it as the UIViewController's main view
self.view = [[[UIViewSubclass alloc] initWithFrame:CGRectMake(0, 0, 320, 460)] autorelease];
}
You can continue setting up the view/subview hierarchy in two ways. One is to add them in the custom UIView's initialization method, like so:
// in the MyView.m file
- (id)initWithFrame:(CGRect)f {
if (self = [super initWithFrame:f]) {
// add subviews here
}
return self;
}
The second way is to continue using the loadView method implemented in the UIViewController subclass, and just using [self.view addSubview:anotherView]. (Alternatively, use the viewDidLoad method in the UIViewController subclass.)
Note: Replace initWithFrame: with whatever the custom UIView's initialization method is (e.g., initWithDelegate:).
Say the view you created is called newView and the controller is newController. The simple approach would be:
newController.view = newView;
But I'd rather subclass UIViewController and override its - (void)loadView and - (void)viewDidLoad methods and create and/or manipulate the view there - that's the way Apple wants you to do it, and for good reason.