Static table view inside UIViewController [Xcode 5] - objective-c

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.

Related

Getting multiple UITableViews in the same view

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!

UITableViewCell as Header or Footer View

I know about UITableView reusable header and footer view
but in my case, i have UITableView Cells, which i need to place also in section headers and also in normal rows
if i use
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
MyCell * cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// ...
return cell;
}
How does it work out with the reusing? (is the message to be available for reuse even than passed), or does this disable the cell reuse
The cells get dealloc'ed when they go off-screen. So they don't get reused. An easy way to verify this is to subclass UITableViewCell with the following
- (void)dealloc
{
NSLog(#"I got dealloc'ed");
}
and observe the console output as you scroll.
These has always worked fine. You first should create a prototype with that name, or register a custom nib with your custom section identifier. HOWEVER , I noticed this breaks in iOS 7 when you add new sections to the table dynamically. Reverting to a plain non-reusing UIView works. Really a shame!

Use UITableViewCell as Button

I read some similar questions about this on Stack Overflow, but none of them had a satisfying answer.
What I am trying to achieve is a "Facebook Sign In Button" from the Settings screen.
I want to achieve this using Static Cells.
But I soon discovered that I could not connect a "Action" to the UITableViewCell using Xcode.
I then tried to achieve the same result using a Custom UITableViewCell with a UIButton inside, but it resulted it a lot of extra styling trouble to make it look exactly like a real UITableViewCell.
Now I managed to make the UITableViewCell to behave like a Button using the following solution:
I changed the Identifier of the "Login Button" UITableViewCell to "loginButton". And I added the following code to the Table View Controller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([[selectedCell reuseIdentifier] isEqualToString:#"loginButton"]) {
NSLog(#"Clicked");
// Execute function to run code for Login button
}
}
Instead of executing a IBAction (which would have been the case if I could just link it like a button in Xcode) I am now going to execute a Function.
This is working like expected. But the reason I created this question is: I want to know if this is the right way to go. Is this ok? Is this bad? Why is this ok or bad? Is there a better solution? Thanks!
Thats a reasonable way to go.
A similar solution using indexpaths would be:
Create an outlet for the Table View Cell from IB.
#property (strong, nonatomic) IBOutlet UITableViewCell *loginButtonCell;
Then implement the didSelectRowAtIndexPath: method.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath isEqual:[tableView indexPathForCell:self.loginButtonCell]])
{
// This will get called when you cell button is tapped
}
}
You can then re-order and without having to modify your code

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.

Filling in data in a Table View problem

I really need help with filling in data in a Table View, where my Table View resides in a Navigation Bar, where the Navigation bar lies in a Tab Bar. After hours of trying add at least 5 data in my Navigation Bar, but it was never able to fill in my Navigation Bar. This was the code I've been using, which is supposed to be the right code: (this code is written before - (void)dealloc:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.text = #"Some value";
return cell;
}
In addition, I tried linked up the dataSource and delegate Outlets to the File Owners, but when I ran the app, when I clicked the Tab Bar Item where my table view is supposed to show my 5 data, it stopped and crashed my app. When I disconnected the dataSource and delegate from File Owners and ran the app again, the Table View is empty in the Navigation Bar with no data filled in, just empty blanks.
So I don't know what else is going wrong here, either I have to link the dataSource and delegate again, which will cause the app to crash again or someone thinks my code is incorrect or is there problems when I insert a Table View in a Navigation Bar and inserting Navigation Bar into a Tab Bar?
Anyone please help me, thanks
Make sure you set the identity of the File's Owner to be a subclass of UITableViewController that contains the code you posted above. You can view the identity by selecting File's Owner in the document window and using the Identity tab (4th tab) in the Inspector Panel.
in .h file declare UITableView *myTableView and
the property as #property(nonatomic , retain) IBOutlet UITableView *myTableView
finally synthesize the variable in .m file.
Now only build your project and go to IB. You will be able to see the IBOutlet in File Owner Attribute Inspector. Connect it to the table you dragged from Library and then connect the datasource and delegate to the owner. save and exit the Interface Builder.
Now Build and Run the project, ur should work fine
Hope this works!!