This is probably a dumb question but I'm just learning. If I have a method that creates a UITableView in code when a button is pressed like this
UITableViewcontroller *contentView = [[UITableViewController alloc] initWithSytyle:UITableViewStylePlain];
contentView.tableView.delegate = self;
contentView.tableView.datasource = self;
[contentView release];
In the UITableView delegate and datasource methods, how do I check if it is this tableView or another TableView? Do I have to have to have an instance variable for this tableView that always points to it for those delegate and datasource methods? Thanks.
You can use tag property. In your code
UITableViewcontroller *contentView = [[UITableViewController alloc] initWithSytyle:UITableViewStylePlain];
contentView.tag == 10;//add this line in your code
contentView.tableView.delegate = self;
contentView.tableView.datasource = self;
[contentView release];
then in your delegate method or datasource methods check
if(view.tag == 10)
{
//do stuff
}
Typically, you’d put the datasource and delegate methods in the table view, not the table view’s parent. That way you could separate the logic for each table view into its own view controller. But, if you must put them all in one class, you can use the tag property of the table view to keep track of which is which.
Related
I just want to load a custom view (with xib) on a viewcontoller's xib or stroy board.What is the best practice to do the same.
I have used awakeAfterUsingCoder function code below.
(id) awakeAfterUsingCoder:(NSCoder*)aDecoder
{
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder)
{
CustomView* theRealThing = (id) [CustomView view];
theRealThing.frame = self.frame;
theRealThing.autoresizingMask = self.autoresizingMask;
return theRealThing;
}
return self;
}
but after using this function my awakeFromNib started calling multiple time.
Please sugegst.
The correct answer currently linked to is overly complicated and buggy, as you have found out. There is a much more standard and better way to do this:
Create an empty XIB
Add a UIView to your XIB so that it is the only top-level object (aside from the proxies First Responder and File's Owner)
Change the class of your new UIView to CustomView
Instantiate the XIB and retrieve your CustomView instance like so:
CustomView *view = [[UINib nibWithNibName:#"CustomView" bundle:nil] instantiateWithOwner:self options:nil][0];
Add it to your view hierarchy in your view controller's viewDidLoad method:
[self.view addSubview:view];
Be sure to override -initWithCoder: in your CustomView subclass in case you need to do any custom initialization. I know this is a lot, so please let me know of any if these steps confuse you or if you get stuck.
I have a UITableViewController subclass that I want to use in conjunction with storyboards in order to set a custom background view. My subclass overrides the init method like so:
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:iPhone568ImageNamed(#"background.png")]];
}
return self;
}
Now when I try and instantiate a new tableview controller (this is interface definition):
#interface AVSelectTableViewController : AVCustomTableViewController
The init method is crashing on any call to self.tableView. Everything looks connected in storyboard (table datasource and delegate points to AVSelectTableViewController parent).
Reading the docs it appears that perhaps the tableView property isn't being set correctly (it just returns the tableview managed by a controller); however I'm not sure how to access it. Any thoughts?
Use awakeFromNib instead of initWithCoder
I have a View Controller that initializes a UIView as its view. That view initializes another UIView as a subview. Both UIViews communicate with the View Controller through a delegate/protocol.
Each UIView creates an instance of the ViewController and makes it equal to the delegate:
ViewController *aDelegate = [[ViewController alloc] init];
self.delegate = aDelegate;
PROBLEM: The View Controller has a variable called (int)selection that is modified by both UIViews. Both views must know how each other modified the variable, but since each has a different instance of the View Controller that communication is impossible. How would I fix this problem?
Thanks a ton
EDIT: Peter mentioned assigning the delegate at the views creation which I like, but how would I do that for the subview since it is created in the UIView and not the View Controller. PS. In reality it is a subview of a subview of a subview so can I create them all in the View Controller and then assign it as the delegate?
Tried assigning the delegate as follows but it continually crashes when I attempt to call a ViewController method from the view:
MyView *mainView = [[MyView alloc] initWithFrame:frame];
self.view = mainView;
mainView.delegate = self;
[mainView release];
The views does not need to know about each other. In your view controller you define a property for the sub view
#property (nonatomic, retain) MyView *myView;
Then you create your sub view and assign the delegate. This can be done in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frame = ...;
MyView *subView = [[MyView alloc] initWithFrame:frame];
self.myView = subView;
subView.delegate = self;
[self.view addSubView:subView];
[subView release];
self.view.delegate = self;
}
Then in your delegate method, which I just guessed how it could look, you can update the view controller as well as the other view.
- (void)view:(MyView *)view didUpdateSelection:(int)newSelection {
self.selection = newSelection;
if (view == self.view) {
self.myView.selection = newSelection;
}
else {
self.view.selection = newSelection;
}
}
It sounds like instead of each view allocating a separate instance of the view controller, you want to assign the instance of the view controller that created the views as the delegate of each view.
One way to approach this is to have the view controller assign itself as the view's delegate when it creates the view.
I realize this is a popular topic, and I've searched through many posts here but haven't found anything that has helped my issue. I'm a beginner, for what it's worth (as you'll see by my question :-)
My app has a tab bar with 3 items. The first loads a UINavigationController that is intended to have 3 "screens" to drill-down through (first: UITableView, second: filtered UITableView, third: UIView). I cannot, for the life of me, figure out how to show the UITableView on the 2nd screen, programmatically.
I'm overriding - (void)loadView since I'm not using IB. At different times, I've tried things like:
- (void)loadView
{
[super loadView];
// first option (thought for sure this would work)
[[self view] addSubview:secondTableView];
// another...
[self tableView:secondTableView];
// another...
[[[[self navigationController] topLevelController] view] addSubview:secondTableController];
}
I do have the table view setup properly with it's delegate and datasource, I just can't figure out how to show the damn thing. The 2nd controller is also inheriting from UITableViewController. Additionally, I don't know how you can say "fit this table view within the navigation title and the tab bar menu". I'm using CGRectMake() currently to guess the sizes, but it seems like there should be a better way (maybe that's why you use IB :-). Either way, that's secondary to even getting something to show up in the first place.
Thanks in advance for any suggestions.
If you're inheriting from UITableViewController your view should be a UITableView not a plain UIView, then when you want to create a view programmatically you should allocate it, initialize it, set its properties and assign it as your controller's view, I haven't tried [super loadView] before but it's creating the tableView for you and assigning dataSource and delegate to self, so you don't have to do that. So it should go like this
- (void)loadView {
UITableView *tempPointer = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) andStyle:UITableViewStylePlain];
self.view = tempPointer; // controller retains view property so we should release it
[tempPointer release];
// If you want your view to be resized automatically (to fit)
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tableView.dataSource = self;
self.tableView.delegate = self;
//...
}
or
- (void)loadView {
[super loadView];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
secondTableView = self.tableView; // or change your code to cope with self.tableView instead of secondTableView...
//...
}
Clear out some uncertainties about view hierarchy creation, retaining etc in the documentation about both UIViewController and UITableViewController if you haven't already.
have you tried:
[Self.navigationController pushViewController:secondTableView];
Hope this helps, if not could you give a little more describing the situation.
I have a core data application which uses a navigation controller to drill down to a detail view and then if you edit one of the rows of data in the detail view you get taken to an Edit View for the that single line, like in Apples CoreDataBooks example (except CoreDataBooks only uses a UITextField on its own, not one which is a subview of UITableViewCell like mine)!
The edit view is a UITableviewController which creates its table with a single section single row and a UITextfield in the cell, programatically.
What I want to happen is when you select a row to edit and the edit view is pushed onto the nav stack and the edit view is animated moving across the screen, I want the textfield to be selected as firstResponder so that the keyboard is already showing as the view moves across the screen to take position. Like in the Contacts app or in the CoreDataBooks App.
I currently have the following code in my app which causes the view to load and then you see the keyboard appear (which isn't what I want, I want the keyboard to already be there)
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[theTextField becomeFirstResponder];
}
You can't put this in -viewWillAppear as the textfield hasn't been created yet so theTextField is nil. In the CoreDataBooks App where they achieve what i want they load their view from a nib so they use the same code but in -viewWillAppear as the textfield has already been created!
Is there anyway of getting around this without creating a nib, I want to keep the implementation programatic to enable greater flexibility.
Many Thanks
After speaking with the Apple Dev Support Team, I have an answer!
What you need to do is to create an offscreen UITextField in -(void)loadView; and then set it as first responder then on the viewDidLoad method you can set the UITextField in the UITableViewCell to be first responder. Heres some example code (remember I'm doing this in a UITableViewController so I am creating the tableview as well!
- (void)loadView
{
[super loadView];
//Set the view up.
UIView *theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = theView;
[theView release];
//Create an negatively sized or offscreen textfield
UITextField *hiddenField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, -10, -10)];
hiddenTextField = hiddenField;
[self.view addSubview:hiddenTextField];
[hiddenField release];
//Create the tableview
UITableView *theTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStyleGrouped];
theTableView.delegate = self;
theTableView.dataSource = self;
[self.view addSubview:theTableView];
[theTableView release];
//Set the hiddenTextField to become first responder
[hiddenTextField becomeFirstResponder];
//Background for a grouped tableview
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Now the the UITableViewCells UITextField has loaded you can set that as first responder
[theTextField becomeFirstResponder];
}
I hope this helps anyone stuck in the same position as me!
If anyone else can see a better way to do this please say.
Try do it in viewDidAppear method, works for me.
I think the obvious solution is to create the textfield in the init method of the view controller. That is usually where you configure the view because a view controller does require a populated view property.
Then you can set the textfield as first responder in viewWillAppear and the keyboard should be visible as the view slides in.
have you tried using the uinavigationcontroller delegate methods?:
navigationController:willShowViewController:animated: