Multiple delegates for a table view - objective-c

Hi I've been googling and I can't find an answer and maybe there's a different way to do this So I'm putting it to the community.
I have a tableview in a UIViewController. The UIViewController is the datasource and delegate for the table view. I then have a second controller which reacts to scrolling in the main UIViewController. Ideally I'd want the second controller to also be a delegate so that scrollviewDidBeginScrolling will fire in both controllers. I want to do this because it makes controller 2 very easy to implement because you'd set it as the delegate and pass in the tableview reference and it would do all the heavy lifting.
Basically can you pass an array of delegates to tableView.delegate? I could see a few situations where you'd want multiple controllers or views to react to an event like scrollViewDidBeginScrolling. Is there any way to accomplish something similar without having to do stuff like
-(void)scrollViewDidBeginScrolling:(UIScrollView *)scrollView{
[anotherViewController scrollviewDidScroll:scrollview];
[otherView scrollViewDidScroll:scrollview];
}
I'm using it for a controller than handles Pull To Refresh for tableviews and I want to make implementation as easy as possible with as few lines/methods in the tableview controller as possible.

You can accomplish what you need but you will need to chain the delegates. The table view will only have one delegate but you can define your own custom delegate method in the view controller that is the delegate of the tableview and have your other view controller set itself to be the delegate of that. Another brute force method would be to just send out notifications and have the view controllers register for the notification.

In you UIViewController1 delegate methods, just send the same call to UIViewController2 delegate methods. E.I.:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[delegate2 tableView:tableView didSelectRowAtIndexPath:indexPath];
// etc...
Edit for comment below. You could subclass UITableView and give it multiple delegate properties or an array of delegates property.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for(id delegate in _delegates)
[delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
// Do nothing else, because the delegates handle everything.
}

What you need is delegate multiplexing. I wrote a class to do just this: https://github.com/aleph7/MultiDelegate

Related

MVVM CoreData FetchedReusltsController

I am trying to start using MVVM with Objective-c but I get some problems with CoreData. I don't know who should handle the fetchedResultsControllerDelegate methods. The viewModel or the viewController?
I think that the viewModel should handle it, but I see too much code to do the same.
Let's say you have an edit button in a view. Edit button is hidden when there are no objects in fetchResultsController and you want to show it when any objects are added.
If you implement NSFetchedResultsControllerDelegate in viewController:
ViewController gets notifications about changes of model
ViewController must notify ViewModel that something happened with the
model
ViewModel has to change value of the editButtonShown
property
ViewModel must notify the viewController to update the
view
If you implement NSFetchedResultsControllerDelegate in viewModel:
model notifies the viewModel about the change
viewModel changes the editButtonShown
property and sends notification to viewController
If you implement these methods in viewController then it gets reference to the model and this should not happened in MVVM
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
I think that correct solution is to implement the NSFetchedResultsControllerDelegatein ViewModel. Then you should have similar protocol to notify the viewController to update the view, but it should work with viewModels, not with the models

Objective-C: Am I Properly Using this Delegate?

I have a mainWindowController that contains a tabView (which I'm using to switch between views on the main window).
I have view controllers (each with a nib file) for each view. One of the views, view A, contains a tableView. I need to use a delegate method to accomplish something.
After an hour or two or web research and reading up on delegates (new concept to me), I finally got my program to achieve the result I wanted it to for view A.
Here's the interface declaration for view A:
#interface ViewAController : NSViewController <NSTableViewDelegate>
- (BOOL) tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
As you can see, I'm using NSTableViewDelegate and I need to disable editing of table columns. The implementation looks like this for the method:
- (BOOL) tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSLog(#"shouldEditTableColumn called");
return NO;
}
I used NSLog to make sure the function is being called.
Now in the SAME view controller (view A), I disable editing by clicking a button:
- (IBAction)turnOffEditing:(id)sender
{
[self.tableView setDelegate:self];
[self tableView:self.tableView shouldEditTableColumn:self.columnTableName row:0];
[self tableView:self.tableView shouldEditTableColumn:self.columnTableName row:1];
NSLog(#"turnOffEditing");
}
As you can see, I get the tableView from the view controller and assign the delegate to self.
I then call the shouldEditTableColumn method on self.
Now, everything works. However, is this the correct way to use a delegate? If I need to use more delegate methods for NSTableView for view A (the only view which will have a table), I'm assuming I can define them in View A's controllers as I did previously?
Usually, the delegate is the delegate from the start. That is, it's a bit strange to set the delegate in the -turnOffEditing: action method. Of course, for my suggestion to work, you'd want to return some dynamic value, like the value of a boolean flag instance variable, from the delegate method.
Also, you shouldn't be calling the delegate method yourself in the action method. That does nothing. The delegate is a thing which the frameworks call when they need to make a decision about how to behave.
So, I'd change your code to something like:
#property BOOL editingDisabled;
- (BOOL) tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSLog(#"shouldEditTableColumn called");
return self.editingDisabled;
}
- (IBAction)turnOffEditing:(id)sender
{
self.editingDisabled = TRUE;
NSLog(#"turnOffEditing");
}
You'd want to set the delegate during setup. A good approach is to simply connect the table view's delegate outlet to your controller in the NIB.

self.TableView not working for a TableViewController inside a ViewController?

I am making a ViewController with 2 tableviews inside it. I am structuring it like
ViewController -> 2 x TableViewController classes. What I don't understand is that if I do [self.tableView reloadData] in the TableViewControllers it doesn't do anything.
If I do [tableViewA reloadData] in the ViewController it will execute the datasource methods in the TableViewController.
How do I call reloadData within the TableViewControllers?
Thanks,
Alan
Edit - This is how I setup the ViewController
if(self.reviewController == nil)
{
self.reviewController = [[ReviewerTableViewController alloc] init];
}
if(self.approverController == nil)
{
self.approverController = [[ApproverTableViewController alloc] init];
}
[self.reviewerTableView setDataSource:reviewController];
[self.approversTableView setDataSource:approverController];
[self.reviewerTableView setDelegate:reviewController];
[self.approversTableView setDelegate:approverController];
self.reviewController.view = self.reviewController.tableView;
self.approverController.view = self.approverController.tableView;
It seems like the datasource methods run once when I initialize them, but reloadData does not work inside.
I am basically just using the datasource methods in the UITableViewControllers and I am calling a method to pull data from the net. Once I get the data, I call reloadData, but the datasource methods are not executed.
Be sure the TableViewControllers' tableView properties are connected to the correct table views.
Are you calling reloadData from the rootViewController? if so, you call
[self.reviewerTableView reloadData];
I would create a UIVIewController that implements the UITableViewDataSource and UITableViewDelegate protocols. Create two outlets, one for each tableview and make sure to wire them up in the interface builder.
then call [tableView1 reloadData];
This seems very strange: you're trying to set the child UITableViewControllers' dataSource and delegates to be some local UITableViews declared (presumably) in your master view controller. It isn't supposed to work like this - the child UITableViewControllers are already the dataSource and delegate to their own implicit table views. There's no need to wired them up to separate UITableViews.
EDIT: I am assuming your "TableViewController" classes are UITableViewControllers. If not, then what you're doing may be valid, but I'd need to see all the code, headers included.

didSelectRowAtIndexPath not called on tableView

I am using tableView in a viewcontroller1 and implementing a didSelectRowAtIndexPath for moving to viewController2 with some data and displaying it on a tableView on viewController2...for now everything is ok, but then when I implement the code on viewController2:
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath) {
// some code
}
After I selecting a row its selected and colored in blue but never stop's in the method didSelectRowAtIndexPath.
What can be the problem?
You should set not only the data source of the table view to your view controller, but the delegate also:
tableView.delegate = self;
You need to set the delegate of your tableView, either in your storyboard or XIB file, or programatically.

What method needs implemented to get an action from the UITableViewCell click / touch?

I'm new to the UITableView and noticed that w/out implementing a method the UITableViewCell simply turns blue when it's touched. What method would I need to add to get some action from this touch directly?
For example, when the cell is clicked I want to pass off the index to another method that will in turn do the same action that is completed by the accessory button click event.
Thank you in advance
You need to implement didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// indexPath.row tells you index of row tapped
// here do whatever your logic
}
didSelectRowAtIndexPath
Link here
You need to assign a UITableViewDelegate to the table view, and implement one or more of the following 2 methods in the delegate class, depending on when you want the event to be fired:
-tableView:willSelectRowAtIndexPath:
-tableView:didSelectRowAtIndexPath: