I want to refactor some Code for better Performance, but my Problem is i´m not sure how to do it. At the Moment i have one UIViewController with a UIScrollView on it.
I also have 20 different Views which (each has its on .h and .m File) can be laid fully dynamically on my UIScrollView. Every Time i start the UIViewController i send a request to my Server and then i get the Response and then i know how many Views i have to put on the UIScrollView.
So you can imagine when theres a lot of different views on my UIScrollView it takes a few seconds because alle Views are getting fully loaded, before the User can finally interact with them.
So my idea is to replace the UIScrollView with a UITableView and change all the CustomViews (UIViews) to Custom UITableViewCells. So only the visible Cells would be loaded at the first start!
Know i have several Problems.
At the Moment, most of the Code from my CustomViews are build with Frames, but i want to change it completely to Autolayout, i don´t think it makes sense to build them all with the IB (xib files ...). So i have to do the whole Autolayout Stuff in Code?
Some of the Custom Views are really big, so they getting really high, and some can be really small. My concern is that the scrolling Perfomance will be really bad... because i cannot really use estimatedRowHeight(A Example: sometimes one Cell can get a height of 1000.0f and the next cell only 40.0f).And in Combination with Autolayout and the Time i have to wait until the Response frome my Server arrives, i think it could be really annoying for the User.
There can be up to 20 different!! custom rows, makes it really sense to use a UITableView in this case? As i mentioned before, they are all very different in their Size and Content!
Here is a little Part of my new Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.node.blocks count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GTBlockView *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
GFBlock *block = [self.node.blocks objectAtIndex:indexPath.row];
//createInterfaceforBlock -- Here the Cell gets called and the Content and the Size gets defined
cell = [[GTAppController sharedInstance] createInterfaceForBlock:block];
// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//GTBlockView is the SuperView of all my Custom Cells
GTBlockView *cell = [self.offscreenCells objectForKey:CellIdentifier];
if (!cell)
{
cell = [[GTBlockView alloc] init];
[self.offscreenCells setObject:cell forKey:CellIdentifier];
}
GFBlock *block = [self.node.blocks objectAtIndex:indexPath.row];
//createInterfaceforBlock -- Here the Cell gets called and the Content and the Size gets defined
cell = [[GTAppController sharedInstance] createInterfaceForBlock:block];
// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
// Get the actual height required for the cell
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
height += 1;
return height;
}
Maybe some of you have some better Ideas or some good Sources?
I have done exactly as you are thinking in an app of my own - I first went down the UIScrollview route, then I changed to a UITableview with many kinds of custom cells. It does make total sense and is very worth it - I gained a massive performance increase from the uitableview. One of the major problems with the UIScrollview is that it will work out the autolayout for all the content in your contentView, which as you say, can take several seconds, but the UITableview will handle this much more quickly and efficiently. So - go for it.
I would strongly suggest you use a unique XIB file for each custom cell. Do the autolayout in each one individually, and that way you are much more likely to avoid problems down the line. Programmatic constraints are far harder to maintain, and autolayout is often challenging.
To get it all working, I did the following : first I had a subclass of UITableviewCell that was the parent class for all the other cell objects. In my case this was called SNFormTableCell (UITableviewCell). Then all other cell objects were based on this class. In my cellForRowAtIndexPath method, I do this :
ReportItem *objectForCell = [self.reportSet reportItemForSection:indexPath.section andRow:indexPath.row]; //my personal data class - just contains the cell data I need
NSString *identifier = [self getNibNameAndReusableIdentifierNameForObjectType:objectForCell.cellType.integerValue];
SNFormTableCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell)
{
[self registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellReuseIdentifier:identifier];
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.contentView.clipsToBounds = YES;
}
[cell setSnFormTableCellDelegate:self]; //i have a delegate that calls back to the tableview when cells are interacted with
cell.reportItem = objectForCell; //put the data object onto the cell to do with as the cell requires
[cell refreshUI]; //update the UI using the data - this is over-ridden by the various subclasses of the cell
The method in there called getNibNameAndReusableIdentifierNameForObjectType .. looks like this (just gets the identifier we need for nib and re-use):
- (NSString*) getNibNameAndReusableIdentifierNameForObjectType:(SNFormTableObjectType)objectType {
if (objectType == SNFormTableObjectTypeBoolean) return #"SNBooleanCell";
if (objectType == SNFormTableObjectTypeDatePicker) return #"SNDatePickerCell";
if (objectType == SNFormTableObjectTypeDropDown) return #"SNDropDownCell";
if (objectType == SNFormTableObjectTypeDropDownPlusSingleLineText) return #"SNDropDownPlusSingleLineTextCell";
... etc
}
Then finally, the parent cell class has a method called -(void) refreshUI. So I put the data object onto that cell - this contains all the data I might need for the cell. The the subclasses over-ride this refreshUI method in their own specific way, to use the data as they need to.
Just to re-iterate, I gained enormously from going down this route. A scrollview with a lot of content, taking 5 or more seconds to load the nibs and calculate the autolayout (on the main thread too, making the app unresponsive), would appear instantly on the UITableview version. So go for it. If you need any more details on how to go about it, let me know.
Related
My TableView delays for loading cell when user scrolls. I found similar questions, but people in those questions using images or downloads something, or have 100+ cells. In my case I have four different cell types in one tableview (is it problem?) and one of them have various count and delays before load new one.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
UITableViewCell *tvCell = [tableView dequeueReusableCellWithIdentifier:identifierUpper];
if (!tvCell) tvCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifierUpper];
tvCell.selectionStyle = UITableViewCellSelectionStyleNone;
_collectionMainInfoView.$width = self.view.$width;
_collectionMainInfoView.$height = self.view.$height*0.45;
[tvCell.contentView addSubview:_collectionMainInfoView];
[tvCell.contentView setBackgroundColor:[UIColor clearColor]];
[tvCell setBackgroundColor:[UIColor clearColor]];
return tvCell;
}
if (indexPath.row == 0) {
EventsCell *eventCell = [tableView dequeueReusableCellWithIdentifier:identifierEvent];
[eventCell setEvent:[Event getNextEvent]];
return eventCell;
}
if (indexPath.row == soldiers.count + 1) {
InviteOtherCell *cellInvite = [tableView dequeueReusableCellWithIdentifier:identifierInvite];
return cellInvite;
}
else {
ProfilesCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.curSoldier = _curSoldier;
cell.delegate = self;
// [cell configureCellWithSoldier:soldiers[indexPath.row - 1]];
[cell setRightUtilityButtons:[self rightButtons] WithButtonWidth:120];
return cell;
}
}
The last ones ( after "else {") has delay before showing
#ProfilesCell.m
- (void)awakeFromNib {
[super awakeFromNib];
_cardView.layer.shadowColor = [UIColor blackColor].CGColor;
_cardView.layer.shadowOffset = CGSizeMake(1,1);
_cardView.layer.shadowRadius = 2;
_cardView.layer.shadowOpacity = 0.2;
}
this code looks litlle bit messy to me.
1) you've defined some view _collectionMainInfoView that will be added to every dequeued cell in first section, thus you're not only retaining that view, but also readding it to your table view cell everytime this delegate method is called.
I would propose to just create own subclass of cell that already contains main info view.
After that, you'll be able to register this UITableViewCell's subclass for your table view, thus you will get rid of this code
if (!tvCell) tvCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifierUpper];
don't hold _collectionMainInfoView in your VC. That smells. How this view will be reused when you'll have multiple cells in first section? You'll probably end up with "jumping view" that will be referenced in several cells.
2) We don't see your implementation of ProfilesCell, thus it's pretty hard to say what could go wrong. If possible, try to setup your cell's view hierarchy directly in it's init. If that's not possible. Don't generate buttons [self rightButtons] everytime this delegate method is called.
You're also not following Objective-C code guidelines. Try to get through them.
For example in here:
[cell setRightUtilityButtons:[self rightButtons] WithButtonWidth:120];
your method parameters should start with lowercase
[cell setRightUtilityButtons:[self rightButtons] withButtonWidth:120];
3) For better readability I'd use switch in your control flow instead of if statement
The only reason that your UITableView scroll not smooth is that you execute long async works in main thread when you load a Cell. Try to find out which piece of code that can execute long work in async?
Try to comment your 2 lines (just for test). What do you do in those 2 set function?
cell.curSoldier = _curSoldier;
and
[eventCell setEvent:[Event getNextEvent]];
When scrolling is not smooth, normally async work is performed when the cell is being displayed. Based on your code I would suspect 2 lines:
1.
cell.delegate = self;
Not really sure what you want to do here. It may cause a loop in the reference?
2.
Sometimes the new optimalisation rules in the compiler have problems with commands within commands. Like in your statement:
[cell setRightUtilityButtons:[self rightButtons] WithButtonWidth:120];
You can try to break this up in 2 separate statements and a new variable.
Unrelated to your tableview code, but creating shadows can cause a performance hit, especially if you are creating a lot. I suggest using theshadowPathproperty, it will speed up your code dramatically.
I am trying to create a project with a custom UITableViewCell. The custom cells never load, they're just blank. At this point in the project what I'm trying to do is placing a UITableViewCell in a .xib, designing it the way I want and specifying its reuse identifier along with tag IDs for the components so that I can use them in code later on.
I've googled a ton and found several tutorials that look like what I want to do, along with many SO questions that have answers that seem applicable. At this point it's probably just my head spinning with too many different angles and solutions.
This is my current attempt at trying to register the custom cell with my UITableView, yet when running this on a device the rows in the table view are entirely blank.
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
UILabel* l1 = (UILabel*)[cell viewWithTag:1];
UILabel* l2 = (UILabel*)[cell viewWithTag:2];
UILabel* l3 = (UILabel*)[cell viewWithTag:3];
l1.text = #"Foobar";
l2.text = #"Foobar";
l3.text = #"Foobar";
I'm pretty certain that I've hooked up all the properties and such correctly, but at this stage I need a fresh pair of eyes to point out the facepalm for me.
The interesting files are FilmerView.m/h/xib and the cell is in FilmerViewCell.xib. When running the app this TableView is in the second tab of the tab bar controller.
Project:
http://speedy.sh/WhhpP/test12.zip
I can't provide a full answer atm but look up the tableview method. registerNib:forCellReuseIdentifier:
Also, stop using that dequeue method. Use the one that includes the indexPath.
Then you don't have to check if the cell is nil afterwards.
EDIT
In viewDidLoad (or somewhere like that)...
UINib *cellNib = [UINib nibWithNibName:#"MyCustomCellXibFileName" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:cellNib forCellReuseIdentifier:#"CellIdentifier"];
Now in the table view datasource method...
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// no need to check cell == nil.
// this method is guaranteed to return a non nil cell.
// if it doesn't then the program will crash telling you that you need to...
// register a class or nib (but we just did this in viewDidLoad) :D
// configure your cell here...
[self configureMyCell:(MyCustomCell *)cell atIndexPath:indexPath];
return cell;
}
- (void)configureMyCell:(MyCustomCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.nameLabel.text = #"Hello, world";
}
Hope this helps.
Make sure that you have set datasource and delegate properties of your tableView.
Make sure that you have implemented (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method and it returns a positive value (>0).
Evaluate the following:
Is the ReuseIdentifier set in the XIB. See Properties Tab in Interface Builder on the right when selecting the cell.
Are the AutoresizingMasks set properly for the labels to be visible?
WrapModes: Which did you select? When having wrapmode WrapWord, is the font size too large for the text to be moved in the next line becoming invisible?
Set the background color of the UITableViewCellss content view to something else than white or transparent, as well as the background colors of the labels to see if the cell is even there.
Manually call numberOfRowsInSection on your table, pass the proper NSIndexPath identifying the target section and see if its greater 0 to confirm that the TableView even attempts to load the data, thus, the cells. ( Alternatively set a breakpoint in the method or do a NSLog. )
Do a NSLog in cellForRowAtIndexPath to confirm that the cell returned is not nil and the method is even called!
So I've made some custom table view cells and they draw correctly and look great, however once I scroll past the edge of the visible cells they start being reused, which is fine, except that when I scroll back the reused cells are still shown and don't redraw. Specifically all the cells look the same except for the top-most cell.
Pictures detailing the occurrence:
How I have this coded up, is when the cells get made if the indexPath.row is greater than 0 add an "overlap effect" which is just a gradient on a uiview placed underneath the custom drawing on the UITableViewCell's contentView.
This is how I add the overlap effect in the UITableViewController's tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"APostCell";
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
CustomPost *aPost = [self.posts objectAtIndex:indexPath.row];
if (indexPath.row > 0) {
[cell addOverlap];
}
cell.postDateLabel.text = [aPost datePostedAsString];
return cell;
}
How would I implement this [cell removeOverlap]?
Try this
if (indexPath.row == 0) {
//remove overlap here
} else {
[cell addOverlap];
}
beacuse, except 1st cell all have overlap.On scrolling the reused cell have the overlap. So for first cell remove the overlap if present.
So after I posted the question I figured it out and, since I had the question and had previously not found any information on the subject figured I would share.
So whenever
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]
is called, the table view either creates a new cell or reuses an old one. When a new cell is created and it is not the top cell (indexPath.row == 0) it adds the overlap to the UITableViewCell. And if it reuses the cell, that method still gets called, regardless what cell is being reused. So naturally once the cell created at the top is reused, the gradient view still gets added to cell.contentView and it stays there even when I'm reusing for the topmost cell again.
In fact adding the overlap view in this way will stack multiple overlap views into the same cell.
So what has to be done (if you intend to customize the cell appearance this way) is to remove the added views before each reuse of the cell. So you have to overwrite the custom tableviewcell's prepareForReuse method and do just that like so.
- (void) prepareForReuse {
[super prepareForReuse];
[self removeOverlap];
}
Be SURE the cell has the overlap view otherwise your app will break by trying to remove views not there. so have something like
- (void) removeOverlap {
if ([self.contentView.subviews count] > 1) {
//This method works based on the assumption [cell addOverlap] adds new view
//underneath existing views - like [self.contentView insertSubview:overlappedView atIndex:0];
[[self.contentView.subviews objectAtIndex:0] removeFromSuperview];
}
}
I'm working on a simple app to display items in a table view. If I return an ordinary UITableViewCell object from tableView:cellForRowAtIndexPath:
static NSString *cellIdentifier = #"EmailCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"EmailCell"];
}
cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
... then the interaction with Dynamic Text works as expected; if the user goes to Settings | General | Text Size, changes the slider value and then returns to my app, all of the visible cells immediately update themselves to use the new font size.
If, however, I return a custom subclass of UITableViewCell, where the XIB contains a UILabel that is set to use a Text Style instead of a System Font, then the Dynamic Text does not work properly. Here is the code I'm using to assign the XIB to the table in viewDidLoad:
[self.table registerNib:[UINib nibWithNibName:#"EmailCell"
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"EmailCell"];
and then this code in tableView:cellForRowAtIndexPath:
static NSString *cellIdentifier = #"EmailCell";
EmailCell *cell = (EmailCell *)[tableView
dequeueReusableCellWithIdentifier:cellIdentifier];
When I first run the app, the visible cells appear with a text size that matches the user's selected preferred text size. However, if I then go to settings and change that size and then go back to my app, all of the visible cells remain with the previous text size. If I then scroll up, I will see two cells that show the new (correct) text size but the rest are still the old size. If I stop and restart the app, all cells now appear with the new (correct) text size.
It seems apparent to me that the tableview is keeping the previously-sized cells in the queue and not automatically updating their font size in response to the user's change of preferred text size. But I'm not understanding why the tableview does make this change automatically when the queue contains ordinary non-subclassed UITableViewCell instances. Is there any way I can get this to work without restarting the app (or without recreating the UITableView instance, thereby emptying the queue)? Is there any way to programmatically (and legally) clear this queue?
Edit: in case anyone's interested in this problem, my drop-in fix for this was to write a general utility method that makes a new tableview, copies over all the relevant properties from the original tableview (included registered cell classes) and then swaps the new one for the old one. Since this is a new table, it generates all-new instances of the queued cells which incorporate the new text size.
This is now handled for you in iOS 10.
http://useyourloaf.com/blog/auto-adjusting-fonts-for-dynamic-type/
Set adjustsFontForContentSizeCategory to YES / true on your label and it'll resize itself automatically when the text size preference changes.
Based on what you described, it would seem that you simply want to reload the table anytime the view comes back on screen after the user has backgrounded it. To achieve this the way I think you want, you need to add the following in your init method for your tableView - it will tell your tableView to reload the cells properly whenever the app is about to enter the foreground:
[[NSNotificationCenter defaultCenter] addObserver:self.tableView selector:#selector(reloadData) name:UIApplicationWillEnterForegroundNotification object:nil];
This way, if the user comes back to the view by opening the app after going to the phone's settings, your tableView should reload and the changes (if any were made) should properly be reflected.
You can see a quick video of the result I tested here:
https://www.dropbox.com/s/pvjuiyofydnxnvd/textsize.mov
EDIT:
Like you said in a previous comment, it would seem like it's something wrong with your nib implementation. The only difference is where/how you update the label property. In the custom cell, I created a label property and a font property, and added the label to the cell in init, and in layoutSubviews I overrode the font. Here's the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LabelCell *cell = [tableView dequeueReusableCellWithIdentifier:#"LabelCell"];
if (cell == nil) {
cell = [[LabelCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"LabelCell"];
}
cell.myLabel.text = _items[indexPath.row];
cell.myFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
return cell;
}
And in the cell itself:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.contentView.frame.size.width - 20, 34)];
self.myLabel.backgroundColor = [UIColor greenColor];
[self.contentView addSubview:self.myLabel];
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.myLabel.font = self.myFont;
}
And here is the same result using custom cells with labels:
https://www.dropbox.com/s/ow2zkb6j9yq2c3m/labelcells.mov
Regarding "clearing the queue", the cells don't get queued up until they are juuuust about to be shown on screen, you can see this by logging a counter value right after you dequeue cell with identifier. If there are 10 cells on screen right now, it only dequeues 10 cells. This is the reason why you use the code if (!cell) {do stuff here that's common for all cells} and then you do things that are specific to each cell afterwards, and why this code works even if you were to assume that reloadData didn't "clear the queue", which I'm not convinced it wouldn't anyway after reading through the UITableView docs.
My drop-in fix for this was to write a general utility method that makes a new tableview, copies over all the relevant properties from the original tableview (included registered cell classes) and then swaps the new one for the old one. Since this is a new table, it generates all-new instances of the queued cells which incorporate the new text size.
Currently I have webviews loading in customized uitableview cells. The problem is the web views have variable sizes. In webViewDidFinishLoad I am able to set the size of the web view based on the actual size of the html document just fine. My problem is the table cells which have already had their height set in heightForRowAtIndexPath before the web views having finished loading. How can I change the height of a table cell after it has already been loaded?
Ideally I feel like I should be able to use some line of code like this.
cellW.frame = cellW.cellWebView.frame;
However I don't seem to have access to cell information in heightForRowAtIndexPath. I've felt like I've explained the situation fairly well, but any code you think I should post I can put up here. I've tried a lot things (so there comments and failed attempts at this everywhere), but the main issue is I can't seem to access cell information in the right places such as heightForRowAtIndexPath. If I could even set cell information somehow in webViewDidFinishLoad, I could simply set the frame of the cell where I am also setting the frame size of the web view.
Below is the setup for my table cell subclass.
#import <UIKit/UIKit.h>
#import "DefinitionsAndConstants.h"
#interface UITableViewCellWebView : UITableViewCell
{
UIWebView *cellWebView;
}
#property (nonatomic,retain) UIWebView *cellWebView;
#end
Here is what I have tried last trying to use part Gavin's code. But of course there is no way to set the table cell now that I've gotten out because cellForRowAtIndexPath is not assignable.
-(void)webViewDidFinishLoad:(UIWebView *)webViews {
[webViews stringByEvaluatingJavaScriptFromString:#"twitterfy()"];
[webViews stringByEvaluatingJavaScriptFromString:#"document.getElementById('tweettext').innerHTML=tweet"];
NSString* h = [webViews stringByEvaluatingJavaScriptFromString:#"getDocHeightMax()"];
int height = [h intValue];
webViews.frame = CGRectMake(0.0f, 0.0f, 320.0f, height);
NSString* i = [webViews stringByEvaluatingJavaScriptFromString:#"return indexPath"];
int ii = [i intValue];
NSIndexPath* ip = [NSIndexPath indexPathForRow:ii inSection:0];
UITableViewCellWebView *tableCell = (UITableViewCellWebView *)[self.tableView cellForRowAtIndexPath:ip];
if (tableCell) {
tableCell.frame = webViews.frame;
}
NSLog(#"Got height from webview %d", height);
}
I would set up a mutable array to read heights from. In viewDidLoad, you'll have to assign some starting values (probably just a bunch of #"44.0", it doesn't really matter, it won't be used for much yet). In your heightForRowAtIndexPath:, just return the number from that array. Then in webViewDidFinishLoad, replace the heights in the array with the height you actually need for that cell (the NSString *h in the code you posted, I believe), and call reloadData on your table view. reloadData will hit heightForRowAtIndexPath:, which will look at the heights array, which now has the actual height needed for that cell, so everything should be shiny.
You should be able to do something like this for your heightForRowAtIndexPath method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *tableCell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
if (tableCell) {
return tableCell.cellWebView.frame.size.height;
}
return 44;
}
This way, if the table cell is visible, it'll set the height according to the height of the embedded web view, otherwise it'll use a default height. In order to make the table view refresh the height of the cell, you'll have to call the following once the web view is sized properly:
[self.tableView beginUpdates];
[self.tableView endUpdates];
That won't make it reload the cells, which could screw things up for you, it'll just make it check the heights again, and the cell height will animate to the new height.