Can't access UITableView Datasource methods using delegate of UISegmentedControl - iphone

I am using a UISegmentedControl in my viewController. With one segment selected, I want the Table's data to be loaded from the NSFetchedResultsController (already setup), and from the other segment, I want data to be loaded from an array.
I am using the segment's delegate method here
- (void)segmentedControl:(SVSegmentedControl*)segmentedControl didSelectIndex:(NSUInteger)index
The problem here is I can't seem to acces the tableView data source methods using the segment's delegate.
For example, it would be good if in the didSelectRowAtIndexPath method, I could do something like if (selectedSegment == 1), then xxxxx.
Does anyone know how I can do this?
I want to push to a different view when a row is selected depending on the segment.

Assuming you've synthesized your segmented control as a property, you can certainly access it from your tableView data source methods.
For example, if your segment is called userSegment you would just do
self.userSegment.selectedSegmentIndex
And then proceed accordingly. e.g. if(self.userSegment.selectedSegmentIndex == 0) {...} else {...}. There are a variety of methods you can do with this index, too. Check out the documentation. One easy example:
NSString *selectedTitle = [self.userSegment titleForSegmentAtIndex:self.userSegment.selectedSegmentIndex];
That's just a simple example, but the point is you can easily use the state of your segment to conditionally populate your tableView data source.
Edit: See the UISegmentedControl Class Reference for more info on selectedSegmentIndex and other properties and methods you can use.

Related

Does the UITableView function visibleCells return custom cell data?

I have a number of custom cell objects (subclasses of UITableViewCell) with a couple of values in them to allow for user interaction within individual cells (like steppers or something). These values are stored within the custom cell class, since calling up to the owner of the table view seemed like a bad idea at the time.
I know of the function (NSArray *) visibleCells. Will that allow me to access the data within the cell objects?
If not, how?
I'm assuming that I can use the built-in functions of the UITableView to pull returned UITableViewCells, but is that sufficent when I'm talking about a subclass of that called, say CustomizerCell?
The function:
- (NSArray *)indexPathsForVisibleRows
Answers an array of index paths. Those index paths can be used the same way your cellForRowAtIndexPath uses the passed index path to access your model.
MyObject *myCustomDataSupportingACell = [myDatasourceArray objectAtIndex:indexPath.row];

A Question about Assign Properties

Edit 2: What I previously planned was probably a bad idea and I now changed my design: My UITableViewController has an array with all the values of my UITextFields and I am using delegation to update the values in the array. (If a value in one UITableViewCell changes, I send a message with the new value and the index of the cell).
Original Question
I would like to create a UITableViewCell subclass. To access my cells, I would like to have an NSMutableArray in my UITableViewController with all the cells. Whenever I create a new cell in - tableView:cellForRowAtIndexPath: I would add it to the array. The cells should however know about this array. I would declare a property like this for the UITableViewCell:
#property (nonatomic, assign) NSMutableArray *cellsArray;
Whenever I create a new cell, I would set its cellsArray to my array.
My (probably simple) question is: Is it correct that cellsArray will hold a pointer to the array in the UITableViewController and when I add stuff to the array of the UITableViewController, the cells will know this too, i.e. can access it?
Edit: The UITableViewCells contain UITextFields. I used to rely on the -cellForRowAtIndexPath: method and the visibleCells array, however when the cells moved out of view, the content of their UITextFields would also be lost. I then decided to store the cells in an array. When the user taps save, I iterate through the array and store the values. Also, I would like to automatically update the enabled property of the save button, depending on whether all cells contain something - for this I need all cells, too.
The cells should know about the other cells so that they can select the next cell when the return/next key on the keyboard is pressed.
If there are better approaches to this, I am glad to hear about them!
Not a direct answer of your question, but this sounds like a very bad design. Why should one cell need to know about its siblings? Any event/change that occurs in one cell and has an effect on the other cells should be handled by the table view controller. The single cells should be separate entities that should have no need to know about the state of each other.
Secondly, there is no need to introduce another array to manage the table cells. The table view already has a property visibleCells that you can access from the table view controller. And should never have to interact with invisible cells anyway because those are managed by the table view and its reuse facility.
I believe the answer is Yes.
My understanding of assign is that you can assign a value to such a variable and the retain count for the original object is not incremented. Similarly you need not release the variable in the object's dealloc method. You may run the risk, however, that the original array goes away and then cellsArray is pointing at something that is no longer there.
I use assign when I want to pass a reference to an object to another object (e.g. a view controller that is going to display or otherwise manipulate the object). And in the latter object, I do not release it's pointer to the object.
You also see assign used with properties that are id's, like
#property (nonatomic, assign) id<SomeProtocol> _myDelegate;
All that being said, with the exception of the id case, often I feel "safer" using retain for the property and being sure to release in dealloc. :-)
Anyway, I think that's the crux of the difference.

Fetching value of label in custom cell

In custom cell I have a UILabel and UISwitch. I want to fetch the text of label when the switch is on. I have kept a method on switch's value changed event but the application is getting crashed.
I'm assuming your mean a custom UITableViewCell. There are a number of ways of getting to the associated label when the switch changes:
If your table is not variable length (so that the cell with the label/switch is unique), when you create the cell cache the UILabel * object and the switch object in your UITableViewController subclass as ivars and associate them together.
If your table is variable length, you need to either maintain arrays of UILabel * and switch *, or you can also subclass UITableViewCell (note that you can provide a custom interface for a UITableViewCell via nib without having to necessarily subclass, you don't mention whether you've subclassed or not), hook up the switch event to go to your UITableViewCell subclass, then read the corresponding label, and/or forward the event to the UITableView subclass (this is a "push" model rather than the "pull" model), sometimes this organization is easier to manage than trying to maintain arrays of objects in your UITableViewCell that track objects in individual UITableViewCells.

Setting ivar in objective-c from child view in the iPhone

Maybe a FAQ at this website.
I have a TableViewController that holds a form. In that form I have two fields (each in it's own cell): one to select who paid (single selection), and another to select people expense is paid for (multiple selection).
Both fields open a new TableViewController included in an UINavigationController.
Single select field (Paid By) holds an object Membership
Multiple select field (Paid For) holds an object NSMutableArray
Both vars are being sent to the new controller identically the same way:
mySingleSelectController.crSelectedMember = self.crPaidByMember;
myMultipleSelectController.crSelectedMembers = self.crSelectedMembers;
From Paid for controller I use didSelectAtIndexPath method to set a mutable array of Memberships for whom is paid:
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[self.crSelectedMembers removeObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
else {
[self.crSelectedMembers addObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
So far everything goes well. An mutable array (crSelectedMembers) is perfectly set from child view.
But...
I have trouble setting Membership object.
From Paid By controller I use didSelectAtIndexPath to set Membership:
[self setCrSelectedMember:[crGroupMembers objectAtIndex:indexPath.row]];
By NSlogging crSelectedMember I get the right selected member in self, but in parent view, to which ivar is pointed, nothing is changed.
Am I doing something wrong? Cause I CAN call the method of crSelectedMembers, but I can't change the value of crSelectedMember.
If I understand your question, the most likely cause is an improper property declaration.
If you want to pass values from one object to another using each objects properties, then you need to make sure to use assign to ensure the properties in one object are pointing at the same instances as the property in the other object.
So in your topViewController you have a property:
#property (nonatomic,retain) NSString crSelectedMember;
Then in your child view controllers you have:
#property (nonatomic,assign) NSString crSelectedMember;
This forces the value into the exact object in the parent controller.
However, this is a very fragile way to pass data between viewControllers. As your app becomes more complicated, it will be impossible to track all the passed data. (Worse, if you run into memory limitations, the parent view controller may unload and not even exist when you try to pass data to it.)
Instead, you should have a single custom object devoted to holding your data. Each view controller should query that object for the data it needs and should write any changes back to that object. The view controllers never communicate directly. This technique allows you to control the data in one specific location instead of spreading it out all over your code and it scales well. You can add an arbitrary number of view controllers to you app without having to worry about tying them all together.
See this post for details: iPhone: How to Pass Data Between Several Viewcontrollers in a Tabbar App

Can I show/hide a certain cell in an UITableView depending on the state of another cell?

I have a UITableView with style "Grouped" which I use to set some options in my App. I'd like for one of the cells of this UITableView to only show up depending on whether another of this UITableView's cells is activated or not. If it's not, the first cell should show up (preferably with a smooth animation), if it is, the first cell should hide.
I tried returning nil in the appropriate -tableView:cellForRowAtIndexPath: to hide the cell, but that doesn't work and instead throws an exception.
I'm currently stuck and out of ideas how to solve this, so I hope some of you can point me in the right direction.
You should remove the data behind the hidden cells from the table view's data source.
For example, if you are using an array, when an action occurs that causes a cell to be hidden, you would remove the object for that row from the array. Then, as the table view's data source, the array will return one less total count and only return valid cells for every row in that count (no nil).
This approach may require maintaining a second array with all of the objects (including hidden).
To update the view, check out reloadRowsAtIndexPaths:withRowAnimation:.
Here's a handy post in which the author provides some source code for performing animations on the currently selected cell:
http://iphonedevelopment.blogspot.com/2010/01/navigation-based-core-data-application.html
He's using this in a NSFetchedResultsController context, but you can see how he's using various calls to add/remove cells & sections.
Now, in your case, you'll need to modify whatever array you're using to host the data used to generate the rows in your tableView when you "activate" your cell, then selectively use:
tableView:insertRowsAtIndexPaths:withRowAnimation:
tableView:deleteRowsAtIndexPaths:withRowAnimation:
tableView:insertSections:withRowAnimation:
tableView:deleteSections:withRowAnimation:
to adjust things accordingly (you can start with tableView:reloadData:, but it's inefficient).
I realize that the API can be a bit daunting, but take the time to read through it and understand what the various calls do. Understanding how the UITableView uses its datasource and delegate, as well as the chain of events that occur when cells are selected/deleted/etc., is important if you want to get things just right (and crash-free).
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:withRowAnimation:]; // or insertRowsAtIndexPaths:withAnimation:
[tableView endUpdates];
Before cellForRowAtIndexPath is called, numberOfRowsInSection is called. You should return the appropriate value of cells in the section there, so if you only want to show 1 cell, return one. The logic what cells are shown has to be implemented partially in both methods