How to change uitableviewcell data in different section? - ios

I want to change the data of two rows in two different sections when one of them is selected so that they will have the same answer. But it is not working:
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:row1 inSection:section1];
cell = [self.tableView cellForRowAtIndexPath:indexPath1];
//DO SOMETHING WITH CELL LABEL
NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:row2 inSection:section2];
cell = [self.tableView cellForRowAtIndexPath:indexPath2];
//MAKE THIS CELL LABEL SAME AS THE LAST ONE
It doesn't work if the second cell is in a different section! Any suggestion?

You will get a nil from cellForRowAtIndexPath: if one of the cells isn't visible at the moment.
You should therefore get the needed entry from your data-model, not from the UI.
Change the needed information there:
NSArray *section1Data = [self.dataModell objectAtIndex:section1];
NSDictionary *dataObject1 = [section1Data objectAtIndex:row1];
[dataObject1 setValue:#"My new Text." forKey:#"theTextPropertyKey"];
NSArray *section2Data = [self.dataModell objectAtIndex:section2];
NSDictionary *dataObject2 = [section1Data objectAtIndex:row2];
[dataObject2 setValue:#"My new Text." forKey:#"theTextPropertyKey"];
Then reload the needed cells in the UI:
NSArray *indexPaths = #[indexPath1, indexPath2];
[self.tableView reloadRowsAtIndexPaths:indexPaths];

Related

iOS Adding dynamic subview into uitableviewcell

I am creating UITableViewCell like this. In that screen, I might have 1 quiz, 2 quiz, etc and 1 poll, 2 polls, etc. It will be dynamic.
As a result, when user scroll up and down, based on data received on my cell, I keep removing previous UIViews and recreating again and again. (I know it is super bad. Now my scrolling got issue.)
NSArray *quizzez = self.cellData[SERVER_QUIZZES];
NSArray *polls = self.cellData[SERVER_POLLS];
NSMutableArray *combinedQuizPoll = [NSMutableArray array];
[combinedQuizPoll addObjectsFromArray:quizzez];
[combinedQuizPoll addObjectsFromArray:polls];
for (UIView *vw in self.quizPollViewCollection) {
[vw removeFromSuperview];
}
for (NSDictionary *quizPollDict in combinedQuizPoll)
{
QuizPollSubView *vwQuizPoll = [QuizPollSubView loadFromNibWithType:QuizPollSubViewNoViewRelated andNavType:self.navType];
[vwQuizPoll setW:CGRectGetWidth(self.frame)];
[vwQuizPoll setDelegate:self];
[vwQuizPoll setData:muQuizPollDict];
[vwQuizPoll setX:0 andY:offset];
[self.contentView addSubview:vwQuizPoll];
offset = CGRectGetMaxY(vwQuizPoll.frame) + 4;
[self.quizPollViewCollection addObject:vwQuizPoll];
}
How shall I make to improve performance? I have studied other similar question in StackOverflow also.
How to make a UITableViewCell with different subviews reusable?
1) I need to have dynamic quiz, poll view (number of quiz, poll will be different for each cell)
2) How can I reference to those view that I created?
First of all I have to say that your approach to use the same cell to put things in a vertical is not the best one. For this kind of situation you should use more than one cell. Something like:
...
DecriptionCell
QuizCell
QuizCell
PollCell
PollCell
PollCell
...
Anyway I'm going to propose you a solution that could help you without change the structure of your UITableView.
Actually I had the same problem a few weeks ago, and I found a very good solution for that.
Basically the main concept is, to Reuse UITableViewCell you shouldn't add or remove views in the configure of the cell because the performance will be affected.
So, the solution that I have used was, use different reuse identifier for each kind of configuration that the cell can have.
The unique requirement is not to have a Nib file for the cell.
If I understood properly your cell can have dynamics Quizs and Polls. Let's go to say that a maximum of 10 Quizs and a Maximum of 10 Polls. Although I'm watching that both have the same View, QuizPollSubView. So let's put a maximum of 20 subviews per cell.
So in the method where you are registering the cells I would do the next:
Class myClass = [CustomTableViewCell class];
NSString *classID = NSStringFromClass(myClass);
for (NSUInteger index = 0; index < 20; index++) {
NSString *identifier = [classID stringByAppendingString:[#(index) stringValue]];
[self.tableView registerClass:myClass forCellReuseIdentifier:identifier];
}
Then in the CellForRow you must dequeue the cell with the properIdentifier, for instance:
NSString *cellID = NSStringFromClass([CustomTableViewCell class]);
NSUInteger numberOfQuizsAndPolls = 3 + 2; //This is 3 quizs and 2 polls, I gess that you can read from the DataModel
NSString *identifier = [cellID stringByAppendingString:[#(numberOfQuizsAndPolls) stringValue]];
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
//then configure the cell
Next, in the initWithStyle:reuseIdentifier: you should create the subviews with empty value, extracting the info from the identifier
NSString *stringNumber = [reuseIdentifier stringByReplacingOccurrencesOfString:NSStringFromClass([self class])
withString:#""];
NSUInteger numberOfSubviews = [stringNumber integerValue];
//here you should add all of your QuizPollSubView with emtpy content.
for (NSUInteger index = 0; index < numberOfSubviews; index++) {
QuizPollSubView *vwQuizPoll = [QuizPollSubView loadFromNibWithType:QuizPollSubViewNoViewRelated andNavType:self.navType];
[vwQuizPoll setW:CGRectGetWidth(self.frame)];
[vwQuizPoll setDelegate:self];
//[vwQuizPoll setData:muQuizPollDict]; YOU CAN NOT SET THE DATA HERE BECAUSE YOU DONT HAVE IT
[vwQuizPoll setX:0 andY:offset];
[self.contentView addSubview:vwQuizPoll];
offset = CGRectGetMaxY(vwQuizPoll.frame) + 4;
[self.quizPollViewCollection addObject:vwQuizPoll];
}
Finally you must to set the proper information in the configure of the cell. Something like:
- (void)configureWithQuizPollDict:(NSDictionary *)combinedQuizPoll
{
for (NSDictionary *quizPollDict in combinedQuizPoll)
{
//get the proper index in the quizPollViewCollection.
QuizPollSubView *vwQuizPoll = self.quizPollViewCollection[index];
[vwQuizPoll setData:muQuizPollDict];
}
}
I hope that it helps you!!
Thanks
PD: If you want to use a Cell with Nib probably we need to subclass the UITableView to add custom dequeue

How Can I Get The indexpath and row in XCODE 5

I have an app that used to work before I upgraded to XCODE 5. I needed to find the row that was selected for a structure I was displaying which has over 100 rows so obviously can be scrolled on the display. The code that used to work is:
NSIndexPath *indexPath = [self.mainTableView indexPathForCell:myCell];
NSInteger row = [indexPath row];
Now, regardless of the row selected, the value of row is always 0. Anyone have any suggestions for me? Thanks.
This worked for me...
CGPoint pos = [pressedButton convertPoint:CGPointZero toView:self.mainTableView];
NSIndexPath *indexPath = [self.mainTableView indexPathForRowAtPoint:pos];
NSInteger row = [indexPath row];
Remember that in Objective-C, you can always send a message nil, and methods that return something (i.e., not void) will return either nil(for an object) or 0 (for a value) when sent to nil (for structs, it is more complicated; read this).
So make sure that:
self.mainTableView is not nil
indexPath is not nil

Border of each UIView

I have to create something similar to above mentioned image. I have a view and i need border after eat view like {breakfast, brunch,etc..}
for giving border I was have following code.
CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(0.0f, 43.0f, menuHeadView.frame.size.width, 1.0f);
bottomBorder.backgroundColor = [UIColor colorWithWhite:0.8f
alpha:1.0f].CGColor;
[menuHeadView.layer addSublayer:bottomBorder];
it works fine for single view but if I have an array for those views and I want to have border after each view using indexPath it doesn't work since it doesn't allow
[array objectAtIndex:i].layer;
help please! Thanks in advance.
If you have array of views you probably should cast:
Change :
[array objectAtIndex:i].layer;
To:
((UIView*)[array objectAtIndex:i]).layer;
EDIT:
Based on #Mischa comment:
Casting is telling the array what object is in it. If you have different kind of objects in array (you really shouldn't!) or to be super safe you can change casting to assign:
id myUnknownObject = [array objectAtIndex:i];
if([myUnknownObject isKindOfClass:[UIView class]]) {
((UIView*)myUnknownObject).layer...
} else {
NSLog(#"%#",[myUnknownObject class]);
}
But base on your comment you contain NSStrings in your array so you can't add layer to this objects. Please check your console, it's probably NSString.
Of course since you mentioned indexPath, and if you're using TableView with rows. You should use the good stuff from reusability and it method:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSDictionary *cellDic = [self.heartbeats objectAtIndex:indexPath.row];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//here goes reusability part like styling and stuff, this will calling only once for every reusable cell. So for example for cells height 44 this will called only 13 times for iPhone screen.
//HERE you should manipulate with layer!
}
//here goes your custom text of every cell - like "Breakfast", "Brunch" and so on. This will calls for every row which is about to show up.
//HERE you should manipulate with text
return cell;
}

Query about UICollectionView

First of all, sorry for the silly question, but i am new to collectionview and little confuse too.
I am working on UICollectionView. I am passing image to it from my plist file. I have 6 to 8 items of array, and every array has 6 items(NSString).
I am using this code..
static NSString *identifier = #"Cell";
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSArray *temp = [list objectAtIndex:indexPath.item];
UIImage *cellImage;
cellImage = [UIImage imageNamed:[temp objectAtIndex:2]];
cell.imageView.image = cellImage;
Now, I want to change index to objectAtIndex:5 when i get flag 1 or 0, and it should be for perticular item.
UIImage *cellImage;
if (myInt == 1) {
cellImage = [UIImage imageNamed:[temp objectAtIndex:2]];
}
else{
cellImage = [UIImage imageNamed:[temp objectAtIndex:5]];
}
cell.imageView.image = cellImage;
If I am doing this then either i get index 2 or index 5 for every item. Is it possible to get index 2 for some item and index 5 for some item based on flag ?? or Is there any other way to do so ?
Any suggestions will be appreciated. Thank you.
Edit :
My collectionview has 3 images(items) in a row. If I tap any icon, it will redirect to the new view to read some documents. There is a done button in that view on bar, which gives a flag value (0/1). Now if I get flag 1 then I want to change collectionview icon for that case only. But here, By this given code all icon replaced by index 5, but I want only first icon from index 5 and other 2 icon from index 2. like Just to differentiate that first doc is reviewed.
sorry if it confuse.
I don't think you want to use myInt that way in this situation. Instead you want to create an array in your collection view controller to keep track of any items that were selected. So, if you had a property called reviewedDocs (pointing to an NSMutableArray), you would add the indexPath of the cell you selected.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self.reviewedDocs addObject:indexPath];
}
Then, in your cellForItemAtIndexPath: method, you would select the image based on whether the current indexPath matches one in the reviewedDocs array.
UIImage *cellImage;
if ([self.reviewedDocs containsObject:indexPath]) {
cellImage = [UIImage imageNamed:[temp objectAtIndex:5]];
}
else{
cellImage = [UIImage imageNamed:[temp objectAtIndex:2]];
}
The image won't change until you come back to the collection view controller, and you reloadData. I wasn't sure what you're using the myInt flag for, but if, for example, you had a done button and a cancel button, you might return 1 or 0 respectively for those two actions. In the viewDidAppear method of you collection view controller, you could then remove the last object from reviewedDocs, if myInt is 0, indicating that the user just cancelled out rather than reviewing the doc (and then call reloadData on the collection view).

nsindexpath access to row to section property causes SIGABRT?

Targeting iOS 5.0 I see SIGABRT when I try to access row or section properties of NSIndexPath object in the following code:
NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:0];
int row = path.row; //SIGABRT
int section = path.section;//SIGABRT
This example suggests using indexPathWithIndex: instead http://developer.apple.com/library/mac/#samplecode/SourceView/Listings/BaseNode_m.html#//apple_ref/doc/uid/DTS10004441-BaseNode_m-DontLinkElementID_6
path = [NSIndexPath indexPathWithIndex:0];
The results remain consistent. Does anyone have an explanation of why this might happen? Is it that we just cannot operate on NSIndexPath in iOS 5.0?
Thanks in advanced.
Try creating the index path using indexPathForRow:inSection:
NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0];
The only thing I can think of is to make sure you have UIKit.framework as one of your frameworks. You can do this by pressing the plus button in the "Link Binary With Libraries" section under "Build Phases" on your target. Also, make sure that you import NSIndexPath.h in the file you're trying to access the index path from.
I've run into this problem before, and this solved it. That's because although NSIndexPath is universal between Cocoa and CocoaTouch, the Cocoa version doesn't have properties row and section.
If you already have UIKit.framework, try using [NSIndexPath indexPathForRow:row inSection:section] instead of [NSIndexPath indexPathWithIndex:index].
I think the problem is that indexPathWithIndex: creates a one-node index path. Same for initWithIndex:. The section and row properties come from the UITableView category to the NSIndexPath class. A one-node index path is invalid for use with a table view because index paths passed to table views must contain two indices specifying the section and row (according to the error message I get when I run your code). The following code creates an index path with two indices and runs without throwing an NSInternalInconsistencyException:
NSUInteger x[] = {0 , 0};
NSIndexPath *path = [[NSIndexPath alloc] initWithIndexes: x length: 2];
int row = [path row];
int section = [path section];
row = path.row;
section = path.section;
Is this what you meant by "operate on NSIndexPath in iOS 5.0"?

Resources