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
Related
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
I got this code in my UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell2";
GamesInfoTableViewCell *cell = (GamesInfoTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
GameInfo *gameInfoObject;
gameInfoObject =[LiveGamesArray objectAtIndex:indexPath.row];
if ([gameInfoObject.GameTime isEqual: #"FT"] | ([gameInfoObject.GameTime rangeOfString:#":"].location != NSNotFound)){
--------------> What to do here? <----------------------------
}
cell.backgroundColor = TABLECOLOR;
cell.homeTeamLabel.textColor = TEXT;
cell.awayTeamLabel.textColor = TEXT;
cell.gameTimeLabel.textColor = TEXT;
cell.liveButton.image = [UIImage imageNamed:#"1675447.png"]; //Load the green image
cell.awayTeamLabel.text = gameInfoObject.AwayTeam;
cell.homeTeamLabel.text = gameInfoObject.HomeTeam;
cell.homeTeamScoreLabel.text = gameInfoObject.HomeScore;
cell.awayTeamScoreLabel.text = gameInfoObject.AwayScore;
cell.gameTimeLabel.text = gameInfoObject.GameTime;
// Configure the cell...
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
So i have a NSMutableArray that contains some objects. And i would only like to populate the table cells with some of the objects. The If statement checks that and if its true then i would like it to go on with the next object/row in the array. I have tried a couple of things but neither did work. Is the only solution to make another NSMutableArray so i can store the ones i want to populate there and then iterate through that one?
Thanks for all the help!!
Yes, you should, you are filtering the array in cellForRowAtIndexPath, which will be called many times. So what I would recommend is to make the array prepared before you load the table.
The key issue that prevents you from coding this up with a conditional inside cellForRowAtIndexPath is that the row from the index path represents a cumulative value of all items that have not been skipped. Hence you need to consider all values in your array in deciding what to print.
Is the only solution to make another NSMutableArray so i can store the ones i want to populate there and then iterate through that one?
This would be a good solution. This is much better than an alternative of traversing the array from the beginning each time, counting the matching objects until you skip row-1 objects, and taking the next one.
Another alternative is building a translation table - i.e. an array of indexes that maps a row to the index in the original NSMutableArray. You can build this table in the method that supplies the row count to your UITableView, and keep it until the next refresh.
Suppose your NSMutableArray looks like this:
0 1 2 3 4 5 6 7 8 9
N Y Y N N Y N Y N N
Top row shows element index. Y is the item you want to keep; N is the item you don't want to show. Your row count method returns 4 (the number of Ys), and builds a table that looks like this:
0 1 2 3
1 2 5 7
The top row is the index of the index array. The bottom row is the index into the original array. Your cellForRowAtIndexPath code needs to pick
gameInfoObject =[LiveGamesArray objectAtIndex:translation[indexPath.row]];
For row 0, translation[indexPath.row] is 1; for row 1, translation is 2; for row 2, translation is 5, and for row 3 it is 7.
as you say "So i have a NSMutableArray that contains some objects. And i would only like to populate the table cells with some of the objects."so there hould be ideally two arrays, 1.LiveGamesArray, 2. create a new filter array like this:
NSMutableArray * filterArray = [NSMutableArray array];
for (GameInfo *gameInfoObject in LiveGamesArray)//can use predicate also
{
#autorelease{
if ([gameInfoObject.GameTime isEqual: #"FT"] || ([gameInfoObject.GameTime rangeOfString:#":"].location != NSNotFound)) {
[filterArray addObject:gameInfoObject];
}
}
}
3.use this filterArray in all data source/ delegate method of your tableview.
hope it will help you.
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).
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];
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"?