viewDidLoad never called in Sub-classed UIViewController - ios

I've run into some trouble with loading a sub-classed UIViewController from a nib. My viewDidLoad function is never called.
The super-class has no nib, but the sub-classes each have their own. i.e.
#interface SuperClass : UIViewController {
}
#end
#interface SubClass : SuperClass{
}
#end
#implementation SubClass
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad{
// Never called
}
The view is loaded from a nib as follows:
SubClass *scvc = [[SubClass alloc] initWithNibName:#"SubClass" bundle:nil];
[self.navigationController pushViewController:scvc animated:YES];
[scvc release];
There is a nib file with this name and it has it's file owner's class set properly.
viewDidLoad is not called in the child or super. Any ideas?

You say you are creating views in code (using loadView) in the super class, but trying to use a nib in the sub class?
According to the UIViewController docs (emphasis mine)
If you specify views using a nib file, you must not override loadView but should instead create a nib file in Interface Builder...
It looks like you may have a conflict there. As a test, comment out the loadView method in your superclass and see where that gets you.

I'm assuming SuperClass implements loadView. So when your SubClass is asked to loadView, you get your SuperClass' implementation, which overrides the normal nib loading mechanism.
I would rethink your design here. Your SuperClass' behavior is quite different from what you want your SubClass to do. Maybe that's not the best relationship there.
But, if you want, you should be able to at least make it work by doing this in your SubClass.m:
-(void)loadView {
IMP defaultImp = class_getMethodImplementation([[self superclass] superclass], _cmd);
/* or alternatively...
IMP defaultImp = class_getMethodImplementation([UIViewController class], _cmd);
*/
defaultImp(self, _cmd);
}
This implements a loadView for your subclass that skips over the loadView of your SuperClass and calls the default implementation instead.
IMO, this is ugly and might need to revisited if your class hierarchy expanded. I wouldn't do this in my own app, I would rethink the class hierarchy instead.

Where is this block located
SubClass *scvc = [[SubClass alloc] initWithNibName:#"SubClass" bundle:nil];
[self.navigationController pushViewController:scvc animated:YES];
[scvc release];
Are you sure it is called ?
I made a testproject to test it and the following works:
In your appDelegate.m file i put the following in the application didFinishLaunchingWithOptions method
UINavigationController *navController = [[UINavigationController alloc] init];
self.window.rootViewController = navController;
SubClass *viewController1 = [[[SubClass alloc] initWithNibName:#"SubClass" bundle:nil] autorelease];
[navController pushViewController:viewController1 animated:YES];
SuperClass.h
#import <UIKit/UIKit.h>
#interface SuperClass : UIViewController
#end
SuperClass.m
#import <UIKit/UIKit.h>
#import "SuperClass.h"
#implementation SuperClass
#end
SubClass.h
#import <UIKit/UIKit.h>
#import "SuperClass.h"
#interface SubClass : SuperClass
#end
SubClass.m
#import <UIKit/UIKit.h>
#import "SubClass.h"
#implementation SubClass
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
NSLog(#"Methods %# called", NSStringFromSelector(_cmd));
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#end
This works for me, make sure you set the right class for your nibFile aswell. Click on the file's owner icon and change the class from UIViewController to SubClass

Try to add:
[super viewDidLoad];

Related

Delegate method not being called, setting delegate to self?

So I'm trying to get a hang of using delegates, and I've watched a few tutorials on how to use them so far. I still find them confusing and after trying to implement one myself, have an issue that I can't seem to solve.
I have two ViewControllers, the first one ViewController contains a UITextField *sampleTextField and a button with the method switchViews. It also contains the protocol declaration with the method sendTextToViewController. SwitchViews is also linked to a segue that switches to the SecondViewController. In SecondViewController the only object is a UILabel *outputLabel When the user taps the button, it calls switchViews and the view changes to SecondViewController, and upon loading outputLabel should be changed to whatever text was entered in sampleTextField in ViewController. However the delegate method sendTextToViewController is never being called. All objects are created in Interface Builder.
Here is the code to make it a bit easier to understand:
ViewController.h
#import <UIKit/UIKit.h>
#protocol TextDelegate <NSObject>
-(void)sendTextToViewController:(NSString *)stringText;
#end
#interface ViewController : UIViewController
- (IBAction)switchViews:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *sampleTextField;
#property (weak, nonatomic) id<TextDelegate>delegate;
#end
Then declared this in ViewController.m
- (IBAction)switchViews:(id)sender {
NSLog(#"%#", self.sampleTextField.text);
[self.delegate sendTextToViewController:self.sampleTextField.text];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController <TextDelegate>
#property (weak, nonatomic) IBOutlet UILabel *outputLabel;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize outputLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)sendTextToViewController:(NSString *)stringText
{
NSLog(#"Sent text to vc");
[outputLabel setText:stringText];
}
I've looked at this and the first answer makes sense, but for some reason it's not working.
I do think that the problem is where I am setting calling [vc setDelegate:self], but not sure how to fix this. Some pointers in the right direction would be greatly appreciated. Keep in mind I'm new to obj-c so if you can explain what you are saying, that would be great. Thank you.
Your are creating a new instance of ViewController but you don't do anything with it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
The SecondViewController needs to have reference to the FirstViewController to be able to set itself as a delegate.
First you don't have to use delegation to do such a program.
A simpler way would be just creating a property in the SecondViewController that you'll pass the content of the textField into it.
Your code doesn't work because you called sendTextToViewController on a delegate that hasn't been set. You have set the delegate to a new instance of ViewController, not the one presented onscreen.

Single ADBannerViewDelegate for multiple views

I'm trying to implement simgle AdBanner instance for multiple views in an iOS app. For implementing AdbannerDelegate in a viewController one has to do
bannerview.delegate= self;
where bannerview is an instance of AdBannerView. This delegate method however has to be implemented in every viewController which amounts up to a lot of repeating code. How can I make up a simple class that implements all delegate methods and then I call use them in every viewController.
I think the viewControllers you are using are subclasses of UIViewController.
And you are saying all the viewControllers have the same delegate methods.
So,what i want to do is create new ViewController class (UIDelgateViewController) by SubClassing UIViewController and add all delegate methods there , and have all the other viewControllers subclass UIDelgateViewController.
The code goes like this,
.h file->
#interface UIDelegateViewController : UIViewController<ADBannerViewDelegate>
#property ADBannerView *bannerView;
#end
.m file ->
#import "UIDelegateViewController.h"
#interface UIDelegateViewController ()
#end
#implementation UIDelegateViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_bannerView = [[ADBannerView alloc] init];
_bannerView.delegate =self;
}
-(void)bannerDelegateMethod{
}
Now your Some viewController ->
#import "UIDelegateViewController.h"
#interface SomeViewController : UIDelegateViewController
#end
#import "SomeViewController.h"
#interface SomeViewController ()
#end
#implementation SomeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubview:self.bannerView];
self.bannerView.frame = ..../
}
If you want to keep always on the screen the same banner while navigating and changing views, you should consider to use View Controller containtment API
A great example is that remarkable sample code written by Apple, that shows how to keep the same banner instance while moving in a tabbar or navigation controller. It could be also a great start for you project.

setting (custom) delegate runs into infinite loop

Am trying to write a simple custom delegate for displaying multiple selection list (after referring various online tutorials, stackoverflow, Apple doc), but in the class that I want to use the delegate, the line where I set the delegate runs into an infinite loop when I run it.
I have shared the source code here
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList?at=master
UIListViewController (where am declaring the protocols)
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList/UIListViewController.h?at=master
And am trying to use the delegate in a UIViewController called View_Exporter
#import <UIKit/UIKit.h>
#import "UIListViewController.h"
#interface View_Exporter : UIViewController <UIListViewDelegate, UIListViewDataSource>
#property (nonatomic, strong) IBOutlet UIView *viewForList;
#property (nonatomic, strong) UIListViewController *listViewController;
#end
View_Exporter.m
#import "View_Exporter.h"
#implementation View_Exporter
#synthesize arraySelectedList;
#synthesize viewForList;
#synthesize listViewController;
#pragma mark - UIListViewController Methods
-(NSArray *) itemsForList {
NSLog(#"View_Exporter itemsForList");
NSArray *array = [NSArray arrayWithObjects:#"Server", #"Memory", nil];
return array;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.listViewController = [[UIListViewController alloc] initWithNibName:#"UIListViewController" bundle:nil];
self.listViewController.listViewDelegate = self;
//[self.viewForList addSubview:self.listViewController.view];
self.listViewController.listViewDataSource = self;
}
#end
But this line in viewDidLoad seems to loop infinitely when I run the code :
self.listViewController.listViewDelegate = self;
Why is this looping infinitely? Am breaking my head since yesterday on this. not sure where am going wrong. can someone please help?
You've written a custom setter for listViewDelegate, at the end of this method you do this:
self.listViewDelegate = delegate;
This just calls the setter method again. Accessing a property via self. is just a way of calling[self setXX:xxx]. In your accessor method you need to set the instance variable directly, in the normal case this would be just
_delegate = delegate;
(The _delegate instance variable is created for you automatically). You can safely remove all of your synthesize statements, they aren't needed any more.

custom protocol doesn't work

In the app I'm working on, I have a UIViewController sublcass and a UIView subclass. in the storyboard the view controller contains the UIview. in the uiview I'm drawing something but I need it to know some values that it should be getting from the view controller. So I created a custom protocol in the view controller .h file:
#protocol SSGraphViewControllerProtocol <NSObject>
- (void)numberOfSemesters:(int)number;
#end
#property (weak, nonatomic) id <SSGraphViewControllerProtocol> delegate;
and in the UIView class I confirmed it as having the protocol above and I implemented its method. However. when I pass a number from the view controller, UIView doesn't receive it. Using NSLog, I figured out that UIView isn't entering - (void)numberOfS:(int)number; am I doing anything wrong? How can I fix it? and is there another way that I can send data from the UIViewController class to the UIView controller?
Here is the full code:
UIViewController.h
#protocol SSGraphViewControllerProtocol <NSObject>
- (void)numberOfSemesters:(int)number;
#end
#interface SSGraphViewController : UIViewController
#property (weak, nonatomic) id <SSGraphViewControllerProtocol> delegate;
#end
UIViewController.m
#implementation SSGraphViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.delegate numberOfSemesters:2];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
UIView.h
#interface SSGraph : UIView <SSGraphViewControllerProtocol>
#end
UIView.m
static int numberOfS = 0;
#implementation SSGraph
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
SSGraphViewController *graph = [[SSGraphViewController alloc] init];
graph.delegate = self;
return self;
}
- (void) numberOfSemesters:(int)number{NSLog(#"YES");
numberOfSemesters= number;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
}
Read This Article, It is best example with Description
http://css.dzone.com/articles/do-not-publishcreating-your
Also read for create Protocol
Following i describe simple Example for How to create protocol
#DetailViewController.h
#import <UIKit/UIKit.h>
#protocol MasterDelegate <NSObject>
-(void) getButtonTitile:(NSString *)btnTitle;
#end
#interface DetailViewController : MasterViewController
#property (nonatomic, assign) id<MasterDelegate> customDelegate;
#DetailViewController.m
if([self.customDelegate respondsToSelector:#selector(getButtonTitile:)])
{
[self.customDelegate getButtonTitile:button.currentTitle];
}
#MasterViewController.m
create obj of DetailViewController
DetailViewController *obj = [[DetailViewController alloc] init];
obj.customDelegate = self;
[self.navigationController pushViewController:reportTypeVC animated:YES];
and add delegate method in MasterViewController.m for get button title.
#pragma mark -
#pragma mark - Custom Delegate Method
-(void) getButtonTitile:(NSString *)btnTitle;
{
NSLog(#"%#", btnTitle);
}
You're creating a view controller instance inside of initWithFrame:, assigning its delegate to be self, and then not keeping a reference to the controller or adding its view into the view hierarchy. This is certainly not what you meant to do. Make the connection in your storyboard instead, by making the delegate property an IBOutlet and connecting them by right clicking on the view controller and dragging from the circle next to the property name onto your view instance.
As an aside I'm not convinced of the utility of using a protocol in this way. If the view needs to know some information to do its job, if should either expose some properties that can be set by the controller, or declare a dataSource protocol and query its dataSource rather than rely on the view controller defining the interface it needs.
// Add an observer to your ViewController for some action in uiview
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveActionNotification:)
name:#"someActionNotification"
object:nil];
// Post Notification and method in your Viewcontroller will be called
[[NSNotificationCenter defaultCenter] postNotificationName:#"someActionNotification" object:self];
// at the end Dont forget to remove Observer.
[[NSNotificationCenter defaultCenter] removeObserver:#"someActionNotification"];

How can we access values of an array added in a viewcontroller class, inside a different UIView class..?

viewcontroller.m has the following code
- (void)viewDidLoad
{
[super viewDidLoad];
self.array=[[NSArray alloc]initWithObjects:#"hi",#"hello", nil];
NSLog(#"%#",self.array);
view *view1=[[view alloc]init];
[view1 addSubview:self.view];
view1.viewController=self;
}
and there is another UIView class where I am trying to access the array :
the .h file :
#import <UIKit/UIKit.h>
#import "ViewController.h"
#class ViewController;
#interface view : UIView{
ViewController *viewController;
}
#property (nonatomic,retain)ViewController *viewController;
#end
and the .m file :
#import "view.h"
#import "ViewController.h"
#implementation view
#synthesize viewController;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"%#",[viewController array]);
}
return self;
}
I checked in other posts of stackoverflow, and the passing of values was mentioned only between viewcontrollers; or the array was declared in the appdelegate and used in the classes(which I want to avoid).
The NSLog in the last code segment above gives null; so can you please help out in accessing the values of this array.
Thanks in advance..!!
You can achieve using this code in your ViewController
#import "view.h"
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *ary = [NSArray arrayWithObjects:#"7",#"5",#"3",#"2", nil];
view *v=[[view alloc] init];
[v initView:ary];
}
And in your view.h file :
#import <UIKit/UIKit.h>
#interface view : UIView
-(void)initView:(NSArray *)ary;
#end
And in your .m file :
#import "view.h"
#import "ViewController.h"
#implementation view
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(void)initView:(NSArray *)ary
{
NSLog(#"%#",ary);
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
Log value will display this :
2013-02-20 20:11:52.731 SampleProject[9414:f803] (
7,
5,
3,
2
)
This line
view *view1=[[view alloc]init];
calls the desired initializer initWithFrame: before you set view1.viewController, so what's happening is that
NSLog(#"%#",[viewController array]);
actually calls
NSLog(#"%#",[null array]);
or (note that is pseudocode)
NSLog(#"%#",null);
What you'll want to do is to use view1.viewController after it is assigned. The best practice would be to make a custom constructor taking UIViewController* as a parameter and use it.
First thing you are calling the init method on the view and checking for viewController in the initWithFrame method which is never called. (But maybe you are calling the initWithFrame: from inside your init method with a default frame. :) ). Second, you are setting the viewcontroller property after you have called the init method, so your viewcontroller is still uninitialized in your initWithFrame method.
Third, instead of passing the whole of viewcontroller to your view to access the array (which kind of goes against MVC pattern), you could probably use just create an instance variable in your UIView subclass and pass just the array.
Then you could follow the answer given by Dilip, preferably using the setter method for setting the array. IMO.

Resources