tableView didSelectRowAtIndexPath doesn't work correctly - ios

I have a really strange problem.
I have a UITableView in a view controller, I can customize all that I want it works. But I want that when I click on a row an other view appear (it is not difficult), so I have done that:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath");
self.myFicheView.hidden=NO;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
But when I click on a row the method is not called. Like it doesn't work I have tried many things and I have found something strange.
When I click briefly on the row nothing happen, but when I click during 3 seconds it work and when I slide my finger on the row too.
Somebody know what is the problem here ?
#interface MapViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
}
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
here the connections inspector of my tableView
http://hpics.li/256d01e

I exactly have no idea how your xib looks like, assuming if the view is coming somewhere in front of your table view, try to bring your tableview in front to that unhidden view.
Assuming if you have put [tableView deselectRowAtIndexPath:indexPath animated:YES]; method only to unhide the selection then there is a property in xib which provides you this facility, by using this you can remove this method and try to run your code. Please give a snapshot of your xib or some of your implemented code for better clarification.

I think you will not call the delegate method
plz include this code to your viewDidLoad method
myTableView.delegate=self;
myTableView.dataSource=self;

Related

The nuances of UITableView

I have been using objective c for a few months now, using different foundation classes and generally playing around with the language.
In my own experience nothing has been more confusing than UITableView; Below is a bit of code that does not do much.
//the header file
#interface SLDataBankListTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
//implementation
#interface SLDataBankListTableViewController ()
#property (strong, nonatomic) SLDataSourceObject* dataSource;
#end
#implementation SLDataBankListTableViewController
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
_dataSource = [[SLDataSourceObject alloc] init];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.dataBankNames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"reuse"];
cell.textLabel.text = [_dataSource.dataBankNames objectAtIndex:indexPath.row];
return cell;
}
#end
I have successfully used this class for over a dozen times and every time I make some stupid mistake like now. Finally I gathered some courage and decided to ask for help.
What are the subtle things, nuances of this class that I don't seem to grasp?
Edit: this is a part of a small program, other parts of it work fine, but the table displays nothing; Some changes have been recommended that are important but did not solve the problem.
It is a little hard to debug without known what is not working, but I see some things which might help you out.
UITableViewController has its own tableview but you seem to have another tableview wired up in a nib. Either use the UITableViewController tableview, or create your own, don't do both.
in cellForRowAtIndexPath you are creating a new cell every time instead of reusing the cells you have.
The delegate methods for the tableview can be called before viewWillAppear. You should create your datasource object earlier. I suggest viewDidLoad:. (Another reason viewWillAppear is a bad choice is that it can be call multiple times, and you can end up creating and destroying many datasource objects for no reason)
Hope that helps.
The big thing to remember about a table view is that it's a way for user to interact with an array of objects. The array is represented by a datasource, and the datasource methods describe what the view needs to know:
how many objects are in the array (called numberOfRowsInSection:)
how to display each one of the objects (called cellForRowAtIndexPath:)
To answer the latter question, the datasource must answer a view. That view's job -- like any view -- is to represent an object for the user. In row the table view uses a UITableViewCell.
The datasource array can be arbitrarily large, so directly mapping UITableViewCells to its elements can get arbitrarily expensive in memory terms. Rather than create a cell for every object in the array, the table view reuses cells.
When a cell scrolls off the top, the "new" one that appears at the bottom isn't new, it's the old cell handed back to the datasource to be reconfigured for the new row. To accomplish this, your datasource is expected to not allocate a new cell, as #JonRose correctly points out, but to ask the table view for a reused cell using dequeueReusableCellWithIdentifier.

How can I allocate and initialize a custom UITableViewCell NOT in cellForRowAtIndexPath?

I won't go into the WHY on this one, I'll just explain what I need.
I have a property in my implementatioon file like so...
#property (nonatomic, strong) MyCustomCell *customCell;
I need to initialize this on viewDidLoad. I return it as a row in cellForRowAtIndexPath always for the same indexPath, by returning "self.customCell".
However it doesn't work, I don't appear to be allocating and initializing the custom cell correctly in viewDidLoad. How can I do this? If you know the answer, save yourself time and don't read any further.
Ok, I'll put the why here in case people are curious.
I had a table view which was 2 sections. The first section would always show 1 row (Call it A). The second section always shows 3 rows (Call them X, Y, Z).
If you tap on row A (which is S0R0[Section 0 Row]), a new cell would appear in S0R1. A cell with a UIPickerView. The user could pick data from the UIPickerView and this would update the chosen value in cell A.
Cell X, Y & Z all worked the same way. Each could be tapped, and they would open up another cell underneath with their own respective UIPickerView.
The way I WAS doing this, was all these cell's were created in the Storyboard in the TableView, and then dragged out of the View. IBOutlets were created for all. Then in cellForRAIP, I would just returned self.myCustomCellA, or self.myCustomCellY.
Now, this worked great, but I need something more custom than this. I need to use a custom cell, and not just a UITableViewCell. So instead of using IBOutlets for all the cells (8 cells, 4 (A,X,Y,Z) and their 4 hidden/toggle-able UIPickerView Cell's), I created #properties for them in my implementation file. But it's not working like it did before with the standard UITableViewCell.
I'm not sure I'm initializing them correctly? How can I properly initialize them in/off viewDidLoad so I can use them?
.m
#interface MyViewController ()
#property (strong, nonatomic) MyCustomCell *myCustomCellA;
...
viewDidLoad
...
self.myCustomCellA = [[MyCustomCell alloc] init];
...
cellForRowAtIndexPath
...
return self.myCustomCellA;
...
If only I understood your question correctly, you have 3 options:
I would try really hard to implement table view data source with regular dynamic cells lifecycle in code and not statically – this approach usually pays off when you inevitably want to modify your business logic.
If you are certain static table view is enough, you can mix this method with overriding data source / delegate methods in your subclass of table view controller to add minor customisation (e.g. hiding certain cell when needed)
Alternatively, you can create cells using designated initialiser initWithStyle:reuseIdentifier: to instantiate them outside of table view life cycle and implement completely custom logic. There is nothing particular that you should do in viewDidLoad, that you wouldn't do elsewhere.
If you have a particular problem with your code, please post a snippet so community can help you
I suggest you to declare all your cells in storyboard (with date picker at right position) as static table and then override tableView:heightForRowAtIndexPath:
Define BOOL for determine picker visibility and its position in table
#define DATE_PICKER_INDEXPATH [NSIndexPath indexPathForRow:1 inSection:0]
#interface YourViewController ()
#property (assign, nonatomic) BOOL isPickerVisible;
#end
Then setup initial value
- (void)viewDidLoad {
[super viewDidLoad];
self.isPickerVisible = YES;
}
Override tableView delegate method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:DATE_PICKER_INDEXPATH] && !self.isPickerVisible) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
And finally create method for toggling picker
- (void)togglePicker:(id)sender {
self.isPickerVisible = !self.isPickerVisible;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
which you can call in tableView:didSelectRowAtIndexPath:
According to your problem, you can create pairs (NSDictionary) of index path and bool if its visible and show/hide them according to that.
Here's what I was looking for:
MyCustomCell *cell = (MyCustomCell *)[[[UINib nibWithNibName:#"MyNibName" bundle:nil] instantiateWithOwner:self options:nil] firstObject];

UITableView within a UIView within UIViewController in iOs Xcode

I want to achieve the following in xcode.
I have a view controller. Within this UIViewController I have a UITabBar. Below them is a UIView. What is the best way to add a UITableView to the UIView? Then being able to click on a UITableViewCell and opening up another UIViewController to show more information about the UITableViewCell?
Here is the current setup of my storyboard:
Could you offer me a solution to this problem? Thanks
You need a solution to your problem but I'm not sure what your problem is.
In storyboard, drag a UIView in your UIViewController. Then drag a UITableView (not controller) in that UIVIew.
You'll be able to see the view hierarchy on the left.
Then link your tableview datasource and delegate to the parent controller.
in your .h file, add the UITableViewDataSource and UITableViewDelegate protocols, also link your tableview as an Outlet.
In your .m files, add the tableview delegate methods (numberOfRowsInSection: and cellForRowAtIndexPath:)
I also suggest adding didSelect: among the tableview methods because, well, you'll need it.
and you're good to go. :)
It's actually the EXACT same thing as creating a tableview, except that your tableview is a subview of a UIView, which doesn't matter at all if it comes to code. The only thing you'll have to be "careful" of is to build your view properly in storyboard, and make sure the constraints don't make your tableview unusable for some reason.
Check one of my previous answers where I explain how to make a tableview and make it load another controller while passing data, which is something you might need if everything I wrote here still confuses you.
FOLLOW UP:
From your comments I understand that this subview of your UIView can be different things ; a tableview, a webview, and so on.
There are many ways to do that, and from my little knowledge I see two that can be easy and reliable (from my <1year experience as a developer...).
Get all the possibilities ready in your parent viewcontroller, if you only have 2 possibilities for example, that's "okay".
The best way is to prepare a container view (it's literally called container view) which would load different OTHER view controllers according to your needs.
I think option 2 is more reliable, because it will split the code into different classes, will allow you to modify each of them independently, and you can easily remove/add new views.
To my knowledge, you'll have some kind of switch statement in your parent controller that will load the desired UIViewController (or tableview or anything). Whatever you do there will just be as usual, but constricted to a smaller view inside another VC.
You can create that container view in storyboard and pre-link every other VC with segues (ToTable, ToWeb, ToCollection) are good examples for segue names that would link that container view to your 3 UIViewControllers.
Note that you can pass data if need be, but you would have all the separate controllers handle their own stuff even though it is visible inside your current vc.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [catagorry count]; //count number of row from counting array hear cataGorry is An Array
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the provided setImageWithURL: method to load the web image
// Ensure you use a placeholder image otherwise cells will be initialized with no image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
cell.textLabel.text = #"My Text";
return cell;
}
these are the basic method to create a basic table view. to load an view controller corresponing to the cell click u can use did select row method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
/* //Pushing next view
cntrSecondViewController *cntrinnerService = [[cntrSecondViewController alloc] initWithNibName:#"cntrSecondViewController" bundle:nil];
[self.navigationController pushViewController:cntrinnerService animated:YES];
*/
[self performSegueWithIdentifier:#"identifier" sender:self];
}

UITableView not displaying content in UIViewController

I have added a UITableView inside a UIViewController in IB, I have set the TableView content to "Static Cells" since that's what I want, and everything seems fine when I haven't added any content to the UITableView. But if I for example change the first UITableViewCell's background color to black it doesn't display black when running the app. I have added UITableViewControllerDelegate and UITableViewDataSource and set the tableView.delage = self;. But still no changes I make to the tableView displays when I run the app.
What can the problem be?
NOTE: I have also tried to add tableView.dataSource = self;, but that just make the app crash.
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 check here: Best approach to add Static-TableView-Cells to a UIViewcontroller?
You will want to use a UITableViewController, not a UIViewController with a UITableView added to it, because you're only supposed to use static cells with a UITableViewController. There are probably ways to hack around it so you can get the static cells to work, but it's much simpler to just use a UITableViewController, and you'll have fewer issues to deal with, especially if you ever change the content of the table.
Seems you have problem with the background issue for UITableViewCell. So don't use background for checking if content is drawing or not.
You can use debugger for this for example or NSLog.
NOTE: the cell has content view that can be modified. I don't remember but seems the cell has not got background property that can be adjusted with a color.
If you tried this line below e.g. - it will no work and color will be white as default color.
[cell setBackgroundColor:[UIColor blackColor]];
Try to add something to the cell for example picture and then you can see the result as I think.
Use this code:
[cell.contentView setBackgroundColor:[UIColor blackColor]]; in this delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
it will help you as I think.
Have you implementede the protocol? ...
another thing is that when implementing the protocol i had an issue when no cell was displayed..
try with this implementation for the given method.
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier=#"Cell";
CobranzaCell *cell = [[CobranzaCell alloc]init];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell = [[CobranzaCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Configure the cell...
return cell;
}
You cannot use the static cells in simple UIViewController subclass. Instead, you should use the instance of UITableViewController. The hack is in your storyboard drag the instance of UIViewController to your storyboard canvas. Then, drag the Container View from objects library and drop it to your UIViewController's view. By default it will create the embed segue with related UIViewController instance. What you want to do - delete this view controller, drag and drop instance of UITableViewController from objects library, then right click and drag from your Container View to just dropped UITableViewController. Chose embed. Now your table view controller gets the size of container view and you can use static cells in it! Hope it will help!

Objective-C: How to declare/define method used on tableView

My initial problem of multiple line selection in a UITableView has been answered in this question. But the answer left me at a point where I can't go on on my own, as I am very new to Objective C and iOS development.
Following daxnitros answer, I want to implement the code he/she suggested:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView indexPathIsSelected:indexPath]) {
[tableView removeIndexPathFromSelection:indexPath];
} else {
[tableView addIndexPathToSelection:indexPath];
}
// Update the cell's appearance somewhere here
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
I still need the methods and I thought I can do it for indexPathIsSelected (for example) like this:
#interface MyTableViewController ()
- (BOOL)indexPathIsSelected:(NSIndexPath *)indexPath;
#end
#implementation MyTableViewController
// ...
- (BOOL)indexPathIsSelected:(NSIndexPath *)indexPath
{
BOOL bIsSelected = NO;
// ...
return bIsSelected;
}
#end
But that doesn't work. The error message is: No visible #interface for 'UITableView' declares the selector 'indexPathIsSelected:' Note: The same happens, if I declare the method in the .h file's interface instead.
Now, what baffles me, is this: [tableView indexPathIsSelected:indexPath] is somehow called on the tableView object and I don't even know why. Is that something I have to take into account in my method declaration/definition? I feel really stupid right now, that I can't even write a method by seeing its invocation.
How do I define and declare the method indexPathIsSelected correctly, so I can use it properly?
In your didSelectRowAtIndexPath, the variable tableView is a UITableView.
Your implementation for indexPathIsSelected is in class MyTableViewController, which is probably a UITableViewController.
UITableViewController and UITableView are different classes.
So you can't find the method indexPathIsSelected on UITableView because it's not implemented there, it's implemented on MyTableViewController which is a different class.
SO... I'm going to take an educated guess and assume that didSelectRowAtIndexPath is part of class MyTableViewController. If this is the case, then
[self indexPathIsSelected:indexPath]
may be the answer (i.e. call indexPathIsSelected in self rather than the table view).
The error message you're seeing is the key to the problem. The method indexPathIsSelected is implemented in your custom class MyTableViewController. However, the UITableView you have is apparently still a basic UITableView. At the very least you'll need to go into the storyboard and set the custom class of the table view controller object to MyTableViewController.
To do this, open the storyboard (or nib) and select the table view controller. Then in the identity inspector (on the right hand side, typically), under custom class, select MyTableViewController from the drop down.

Resources