Getting multiple UITableViews in the same view - objective-c

I have two UITableViews named TableView1 and TableView2 in the same view, and I'm having trouble populating them. I've used some suggestions in other SO questions, but I haven't been able to get them to work (see description below). In my code, I've set weak outlets in the relevant .m file as follows:
#property (weak, nonatomic) IBOutlet UITableView *tableView1;
#property (weak, nonatomic) IBOutlet UITableView *tableView2;
Then, in numberOfSectionsInTableView, NumberOfRowsInSection, CellForRowAtIndexPath, and didSelectRowAtIndexPath, I've put in code similar to the following. It is worth noting that tableView1 is grouped and tableView2 is plain, so there are additional header-related methods (for tableView2) and a method for section title for tableView1 that I have not put in these checks for, since they can only be called by one table view.
- (UITableViewCell *)numberOfSectionsInTableView: (UITableView *)tableView {
if (tableView == self.tableView1) {
// stuff for tableView1;
} else {
// stuff for tableView2;
}
}
Unfortunately this gives the result of only displaying the second table view. As per other SO posts, I've also tried the tag method by setting
- (void)viewDidLoad {
...
self.tableView1.tag = 33;
self.tableView2.tag = 34;
...
}
...and NSLog confirms that the tags are being set correctly, and I know that these tags aren't used anywhere else in the storyboard. After replacing all the if (tableView == self.tableView1) checks with if (tableView.tag == 33), the first table view still did not show up when run. I logged the tag of the tableView in numberOfSectionsInTableView and discovered that tableView.tag was always 34, even though I had specifically set tableView1.tag to be 33.
EDIT: Making sure the delegate and dataSource for both table views are set (thanks to commenters) now logs tags of both 33 and 34, as desired, but the first table view is still not appearing.
Is there an obvious reason I'm missing as to why neither of these two methods are working? Or is there a more efficient way to implement this? Thanks!

Related

Static table view inside UIViewController [Xcode 5]

I'm aware of the problem that one is not able to have static table view content in a UIViewController in
I don't get a warning/error but he also doesn't compile. Is there a trick to it or do I have to use the old ways around it?
Thanks in advance.
UPDATE: With the latest update (Xcode 5.1) it seems that it's no longer possible to put static cells inside regular UIViewController. My answer still applies for UITableViewController though.
Yes, you can have static table view content in UIViewController.
All you need to do is:
-Create the table's static cells in interface builder and design them the way you like.
-Make the UIViewController implement table view's data source and delegate:
#interface MyViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
-Connect the table view's delegate and dataSource to the view controller in interface builder
-Implement -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section to return the number of your cells. (e.g. return 10, yes simple as that)
-Connect your cells to your code as IBOutlets in Interface Builder. IMPORTANT: Make sure they are strong, weak won't work. e.g. #property (strong, nonatomic) IBOutlet UITableViewCell *myFirstCell;
-Implement -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to return the correct cell at index path. e.g:
int num = indexPath.row;
UITableViewCell *cell;
switch (num) {
case 0:
cell = self.myFirstCell;
break;
case 1:
cell = self.mySecondCell;
break;
}
return cell;
If you apply all these steps, you should have working static cells that works for tables with not many cells. Perfect for tables that you have a few (probably no more than 10-20 would be enough) content. I've ran the same issue a few days ago and I confirm that it works. More info on my answer here: Best approach to add Static-TableView-Cells to a UIViewcontroller?
There's a way to improve Can's answer.
Connect your cells to code not as IBOutlet but as IBOutletCollection. If you name it as e.g. cells your code will look like this, which makes it slightly cleaner:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.cells.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.cells[indexPath.row];
}
The order in which you connect cells to outlet collection will be the order you see when run the app.
I can think of supporting several sections by linking their cells to several outlet collections.
This is my try:
I have created container view and Table View Controller. Then I opened source code of Storyboard and changed destination identifier of container view to table view container identifier. Now make table view controller static...
UPDATE:
Just Ctrl+Drag from ContainerView to UITableViewController!
UPDATE 2:
Set embedded view controller class to smith like MYStaticTableViewController, witch should only have this method to provide -prepareForSegue calling to parent view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([self.parentViewController respondsToSelector:#selector(prepareForSegue:sender:)])
[self.parentViewController prepareForSegue:segue sender:sender];
}
UPDATE 3:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if ([self.parentViewController respondsToSelector:#selector(shouldPerformSegueWithIdentifier:sender:)])
return [self.parentViewController shouldPerformSegueWithIdentifier:identifier sender:sender];
return YES;
}
Can's solution does break in XCode 5.1 :(
I found a workaround which builds off the same basic idea, but unfortunately requires a little more involvement: http://www.codebestowed.com/ios-static-tableview-in-uiviewcontroller/
To summarize, you can add TableViewCells directly to views (and create IBOutlets from them, etc), but in order for them to get "moved" to the TableView properly, you need to remove them from the view in code, and you also need to set Auto-Layout constraints in IB.
As Dannie P mentioned above, using an IBOutletConnection is the way to go. To clarify on this a bit further:
Take the first cell from your static table view and ctrl+drag it into your UITableViewController. On the connection property window, select Outlet Collection on the Connection pull down menu.
Your should end up with code similar to this:
#property (strong, nonatomic) IBOutletCollection(UITableViewCell) NSArray *cells;
Next, ctrl+drag over all the rest of your cells (one at a time) onto the property you created above in the order you want them to appear in your static table view.

didSelectRowAtIndexPath, pushViewController and a little lable

I have a table controller in which I use didSelectRowAtIndexPath to navigate from the pushed cell to another view. In it I initialize new view controller and push some data in it. After that I do pushViewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
ServicesModel *service = [services objectAtIndex:indexPath.row];
ServiceViewController *serviceViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ServiceView"];
serviceViewController.serviceModel = service;
NSLog(#"Set model %#", service.title);
// Pass the selected object to the new view controller.
[self.serviceController pushViewController:serviceViewController animated:YES];
}
In my ServiceViewController I have a label serviceTitle and ServiceModel property for selected service
#property (weak, nonatomic) IBOutlet UILabel *serviceTitle;
#property (strong, nonatomic) ServiceModel *serviceModel;
Using viewDidLoad I'm trying to change text of the label
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"viewDidLoad %#", self.serviceModel.title);
self.serviceTitle.text = self.serviceModel.title;
}
Also I'm trying to access model in viewDidAppear
- (void) viewDidAppear:(BOOL)animated
{
NSLog(#"viewDidAppear %#", self.serviceModel.title);
}
but when view opens, label is empty. Why? What am I doing wrong? The most strange is the log:
(-[ServiceViewController viewDidLoad]) (ServiceViewController.m:43) viewDidLoad (null)
(-[ServicesTableViewController tableView:didSelectRowAtIndexPath:]) (ServicesTableViewController.m:127) Set model Google.com
(-[ServiceViewController viewDidAppear:]) (ServiceViewController.m:36) viewDidAppear (null)
It shows that viewDidLoad fires before I assign the model property. And in viewDidAppear model property is still null. How it can be?
You have two problems. The first one, as 0x7fffffff mentioned, is that you're instantiating your controller incorrectly (it should be initWithNibName:bundle: if made in a xib, and like 0x7fffffff said if in a storyboard).
Second, you can't access the label in serviceViewController from didSelectRowAtIndexPath, because its view has not been loaded yet. So, instead of setting the label in didSelectRowAtIndexPath, you should have a string property in serviceViewController, and give it the value service.text. Then in viewDidLoad, you can populate your label with that string.
Is the label missing altogether, or do you see it and it just didn't receive updated text? If the label is missing, then it's probably a problem in how you're creating the view controller. If for example, you're using storyboards, you should be accessing the view controller like this:
ServiceViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SomeStoryBoardID"];
Instead of this:
ServiceViewController *serviceViewController = [[ServiceViewController alloc] init];
If however, you can see the label, but it just hasn't updated it's text, the first thing you should to is examine the connections inspector in Interface Builder, and verify that the IBOutlet for the label is properly linked.

Adding Text Field Data to Table Cell

How I can store text field data in a view controller into a tableView cell in a TableViewController With Xcode using data source?
That means when the user taps "+" it will show another view that has the text field. When the user enters the text and presses save, the entered data will be stored as a table cell.
First make sure you understand data sources. Then you have to implement
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.data.count;
}
- (NSView *)tableView:(NSTableView *)tableView
viewForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row {
NSTableCellView * result = [tableView makeViewWithIdentifier:#"identifier" owner:self];
result.textField = #"Your special string";
return result;
}
After having setup it in IB like this and having connected the outlet of the Table View data source to your custom objects class (the class the above code is in) it should look like this
Please notice I used the same identifier as in the code so that I can get the created table cell view back easily.
self.data could be an array for example in which you store all your underlying objects (for the cell creation).
Of course you could also add any kind of UI elements to the cell view as well. In this case I use a custom subclass for the cell view. You would have to do something like this then (and set your class as the class of the cell view within IB of course. This is the part in the screenshot that has an NSTableCellView currently in it. It had to be MyGreatCellView from now on):
#interface MyGreatCellView : NSTableCellView {
IBOutlet NSTextField *files;
}
#property (assign) NSTextField *files;
Then you could also refer to result.files in the tableView:vieForTableColumn:row for example.
If something is unclear, just ask.
Getting the UITextField data onto a TableView Cell.
Here is a query for some one for the same issue.I think it will help you.

Can I use properties to determine the class of an object?

I have a custom UITableViewCell created in IB.
All my cells will have this general layout. However,in some cells, the two white views will be classA and in other cells the two white views will be classB. (Both subclasses of UIView). I tried to assign the specific subclass of the two views using properties.
I set the two views as properties of the cell
#property (nonatomic, retain) IBOutlet UIView *leftView;
#property (nonatomic, retain) IBOutlet UIView *rightView;
And in my view controller where I make the table view, I tried creating an object of type subclassA and assigning it as leftView, so that leftView will be of type subclassA. In other cells, I would create an object of subclass B and set it to leftview, so that in those cells, left view would be of subclass b.
//equationTextField is a subclass of UIView
EquationTextField *textField = [[EquationTextField alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; // arbitrary frame
cell.leftView = textField;
This code doesn't work, however. Is there a better way to assign the specific class of my views?
What you are doing is fine, but you may want to investigate having two different cell types (with your custom views already embedded) to improve performance - each could have a different reuse identifier which you would choose depending on the index path. Creating views every time in cellForRowAtIndexPath is never a good idea.
You could even derive both types from the same cell, just use the different reuse identifier and add in the correct subclasses only when first creating the cell.
You can check to see if cell.leftView is your EquationTextField if needed:
if([cell.leftView isKindOfClass:[EquationTextField class]]) {
NSLog(#"View is EquationTextField");
}
else {
NSLog(#"View is not EquationTextField");
}

Populate text in one textfield from text in another

Working on an experiment on the iPad. Tried some variations on how to do this, but I can't seem to get it to work correctly...
I tap a UIButton on my MainViewController and a TextEntryModule is added to the view. TextEntryModule is its own class (for multiple instantiation) and it contains a UITextView called TextEntry (this all works at the moment).
I tap on the TextEntry UITextView and it brings up the keyboard and another view (located in MainViewController) with a UITextView called TextPreview. (this also works at the moment).
The part I'm having trouble with is synching the two UITextViews. The idea being that when I type into TextEntry, the text in TextPreview will also be updated.
Outlets are linked properly for the text fields, but I think I'm missing something "obvious":
TextEntryModule *tm = (AnnotationModule *)currentModule;
TextPreview.text = tm.TextEntry.text
Thanks in advance!
UITextView: delegate.
- (void)textViewDidChange:(UITextView *)textView
Then assign it the value of the other textview in this method.
Edit
#interface MainViewController <UITextViewDelegate> {
...
}
...
#end
Then you implement this method in the implementation file of MainViewController
#implementation MainViewController
//More code
- (void)textViewDidChange:(UITextView *)textView {
TextEntryModule *tm = (AnnotationModule *)currentModule;
TextPreview.text = tm.TextEntry.text
}
#end
Then you will have to set the TextEntryModule object's delegate to self since the controller now conform to the protocol and can "act" upon this notification.
You need to become a UITextFieldDelegate and monitor when text changes in the one field and then update the other field. Take a look at the documentation on it.