Even though I am setting delegate and datasource, the data source methods are never being called.
I have a ViewController that adds a subview as such:
EVPhotoCollectionViewController *pc = [[EVPhotoCollectionViewController alloc] initWithNibName:#"EVPhotoCollectionViewController" bundle:nil];
self.damagePhotosView = pc.view;
Inside EVPhotoCollectionViewController I have delegate and datasource wired up in the xib, but also via code as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView reloadData];
}
None of the datasource methods are ever called. I have verified self.collectionView is not null when it calls reloadData.
Thanks!
I think there are several things wrong here--and there are some complexities to view controller containment that you may need to read up on.
First off, you're not adding the EVPhotoCollectionViewController view as a subview of your vc, eg:
[self addSubView:pc.view];
Also, you're not setting a frame for the EVPhotoCollectionViewController, so depending on how it's implemented, it might not show up with the right size/position.
Lastly, it doesn't look like you're retaining the EVPhotoCollectionViewController anywhere. Its view will be retained by the view hierarchy, but it looks like the instance of EVPhotoCollectionViewController will be dealloc'd once the function creating it goes out of scope.
View controller containment: How does View Controller Containment work in iOS 5?
Related
I'm facing a strange behavior of a UITableView. I have a View Controller with a UIView, let's call it view A.
Inside UIView A I'm calling another view from a UIViewController, called view B.
HomeViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UIView *B = [[BViewController alloc]init].view;
[self.A addSubview:B];
}
Inside B, I have a UITableView C.
BViewController.m
- (void) viewDidLoad
{
C.delegate = self;
C.dataSource = self;
[self.view addSubview:C];
}
This UITableView is loading correctly but when I just tap on the screen all of the table's content is gone. Just an empty table remains.
In your view controller B made property of type A and name it to delegate and set it with instance of A and set that delegate property to your table view' datasource and delegate instead of self. Because in viewdidload of B you are setting delegate and data source as self that means instance of B and your table view is being shown on viewcontrollet A. So A's instant would be the delegate of tableview. So set tableview's delegate and datasource to self in vc A or as i mentioned in above lines.Or you should add vc as childviewcontroller.
Following the official documentation of View Containers my problem was solved.
I finally made the switch to Storyboards and i am having issues loading custom controllers which was pretty easy to do when using interface builder.
I have ViewControllerOne with two components: A UIView and UITableView as the subview.
I want the UITableView to be controlled by a custom tableview controller. If this was Interface builder i would have dropped a tableview controller onto the XIB, linked to the custom controller and made the connections and it would have been done.
Using storyboard, i don’t believe its possible to drop a UIViewController/UITableViewController onto a scene which already has a view controller, i relied on Objects to achieve this.
So i added a Object onto the scene and linked it to my custom tableview controller. I set up delegate/date source for my UITableView to point to the custom controller. I finally connected the UITableViews outlet to the custom controller.
When i compile this, the custom controllers delegate (for the table view) gets called but the viewDidLoad is never called.
The only way i can invoke viewDidLoad is if i move the UITableView out of ViewControllerOne. My understanding was that even though there is one view controller for a scene i can still manipulate the subviews using custom controllers.
Am i misunderstanding something or is there is a solution for this ?
Some screenshots
There is a bit of magic in that. Call self.view from awakeFromNib and flow will back to the rails
- (void)awakeFromNib
{
[super awakeFromNib];
// here comes the magic - call self.view and view will load as expected
NSLog(#"awakeFromNib %#", self.view)
}
you can call it from initWithNibName:bundle:
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
NSLog(#"awakeFromNib %#", self.view);
}
return self;
}
the point is to call self.view because apparently something is done inside.
If I have understood your question correctly:
1 Open the storyboard and navigate to the table view controller that you would like to be of your custom type.
2 Click on the identity inspector in the right hand side panel.
3 Set the class to what it should be.
I am using something like:
VC = [[SettingsViewController alloc] initWithNibName:nil bundle:nil];
viewDidLoad is not called yet.
But when I do:
VC.view.frame = CGRectMake(...);
At this point viewDidLoad is called.
But the issue is, that the view dimensions that I am passing in the above code statement is not used in the viewDidLoad method.
I think it sees that view is being used, so it is time to load the view, and after loading the view it must be assigning the frame dimensions to the view. But what if I want that view dimensions set before viewDidLoad gets called, so that I can use those dimensions in the viewDidLoad method..
Something like initWithFrame..
Also, I don't have the view dimensions in the view controller. I have to assign the view dimensions from outside of the VC.
So probably after calling initWithNibName:bundle: method I can save the view frame dimensions in some variable.. but that doesn't look like a clean solution, does it?
viewDidLoad is called when the view did load. (surprise)
so by the time you call VC.view, before it return, the viewDidLoaded will be executed and then the view is returned, and set the frame.
so from your current approach, it is not possible
anyway, why you need view frame in viewDidLoad? maybe you can move that part into viewWillAppear / viewDidAppear which is only get called when the view is about to present
You can do something like this:
In the interface
#interface SettingsViewController : ... {
CGRect _initialFrame;
}
...
- (id)initWithFrame:(CGRect)frame;
#end
In the implementation
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
_initialFrame = frame;
}
return self;
}
- (void)viewDidLoad
{
self.view.frame = _initialFrame;
[super viewDidLoad];
}
and then from the class you use these controller:
VC = [[SettingsViewController alloc] initWithFrame:CGRectMake(...)];
I have an odd case -- a view controller that creates its own view in loadView and which is then added to an existing view.
Here is the code that creates and adds the VC:
self.doneButtonViewController = [[DoneButtonViewController alloc] init];
[self.view addSubview:self.doneButtonViewController.view];
This code is executed in viewDidLoad of the "parent" VC.
The odd thing is that the viewWillAppear method of the added VC is never invoked (nor is viewDidAppear), but the viewWillDisappear method of the added VC is invoked (at the appropriate time), just as one would expect.
Any clue as to why viewWillAppear is not getting invoked?
The application isn't aware of the subview's view controller if you do this, you need to introduce view controller containment to make the root view controller aware. Doing so will handle any events like this.
Because loadView could be called more than once pre iOS 6, I'd advise creating the view controller within init, and then add the subview within loadView. It should be like this:
- (id)init {
...
self.doneButtonViewController = [[DoneButtonViewController alloc] init];
[self addChildViewController:self.doneButtonViewController];
[self.doneButtonViewController didMoveToParentViewController:self];
...
}
- (void)loadView {
...
[self.view addSubview:self.doneButtonViewController.view];
...
}
See "Implementing a Container View Controller" at http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
As for me, adding child view controller in parent view controller can solve the problem that "viewWillAppear" of the child view controller not get called.
I would like to use my viewDidLoad function in my tableViewController.
How can I make viewDidLoad run in my controller?
tableViewController = [[TableViewController alloc] init];
UITableView *tableView = [[UITableView alloc] init];
tableViewController.view = tableView;
....
From Apple documentation:
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.
So you can try to instantiate it from NIB or overwrite the loadView method. Another step from Apple documentation:
If you cannot define your views in a storyboard or a nib file, override the loadView method to manually instantiate a view hierarchy and assign it to the view property.
viewDidLoad will be called when the view is actually loaded, which will happen after you present your view controller, by, e.g.:
adding it to a navigation controller,
adding it to a tab bar controller,
presenting it modally.
This is the missing bit in your code. If you explain how you would like to present your view controller, I may help further. Also, have a look at this: Presenting View Controllers.
(I assume the fact that you tried to override the view property of your table view controller was just an attempt "to make things work" -- but you do not need to do anything about that, the view controller will be correctly set up with a table view inside of it).
tableViewController = [[TableViewController alloc] init];
tableViewController.tableView // This is your newly generated tableview
viewDidLoad will be called after you assign the tableView to another parentview