I have a super ancient Objective-C chat code based on UITableView. There is only one type of cell, let's call it ChatTableViewCell
. In our chat there are more than 10 types of messages (text, image, event, etc). ChatTableViewCell
itself is responsible for a bunch of logic, such as:
- Which side to display the avatar on (incoming or outgoing message);
- Hide avatar if it is 2nd+ message from the same user (message grouping);
- Reactions to the messages with emojis (users can react to any type of message);
- Label to show the delivery status for outgoing messages; – etc.
ChatTableViewCell
also holds a container view into which a needed subclass of UIView
(ImageMessageView
, TextMessageView
, EventMessageView
) is added as a subview.
In
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
method message is taken by its index from the array of messages. Before today, each message object would contain all information, to be displayed in the cell like message text, or, if it is an event message, for example, it would contain all info items such as location name, time, date, number of people who RSVP'ed, etc.
Chat code is an extreme legacy, there is no AutoLayout used anywhere, at all.
Each cell height is determined in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
In this method message is taken by its index and depending on the its type, the message is passed to a static method of the needed subclass of UIView (embedded to the ChatTableViewCell
). Those static methods have an ugly manual height calculation like this:
+ (CGSize)neededSizeForContentWithEventInfo:(SBEventInfo *)eventInfo
{
CGFloat contentHeight = 0;
UILabel *label = [SBEventBubbleView labelForType:LabelTypeIcon];
label.text = @"";
CGRect frame = [SBEventBubbleView frameForLabelText:label];
contentHeight += frame.size.height;
label = [SBEventBubbleView labelForType:LabelTypeTitle];
label.text = eventInfo.name;
frame = [SBEventBubbleView frameForLabelText:label];
contentHeight += frame.size.height;
label = [SBEventBubbleView labelForType:LabelTypeTime];
label.text = eventInfo.time;
frame = [SBEventBubbleView frameForLabelText:label];
contentHeight += frame.size.height;
label = [SBEventBubbleView labelForType:LabelTypeAddress];
label.text = eventInfo.address;
frame = [SBEventBubbleView frameForLabelText:label];
contentHeight += frame.size.height;
contentHeight += kEventBubblePaddingTop + kEventBubblePaddingBottom;
contentHeight += (kEventBubbleContainersSpace + kEventBubbleButtonHeight);
return CGSizeMake([SBEventBubbleView maxWidth], contentHeight);
}
+ (CGRect)frameForLabelText:(UILabel *)label
{
return [label.text boundingRectWithSize:CGSizeMake([SBEventBubbleView maxWidth] - kEventBubblePaddingLeft - kEventBubblePaddingRight, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:label.font} context:nil];
}
PROBLEM:
Now there is a new type of message that doesn't contain all pieces of info readily available. Instead it only contains some ID, which is passed to a corresponding subclass of UIView, and then inside this view there is a network call, which uses this ID to fetch all the information. Having this asynchronous call, makes it impossible to calculate height of this message on the screen using ugly old-fashioned approach with static methods.
What can I do in this situation? Is it possible to return some temporary/dummy height from
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath```
and then, when network call in the cell is done, somehow recalculate the height of the cell having all pieces of data available?
Once again, all this ton of code is entirely frame-based, unfortunately there is no AutoLayout used at all. Otherwise, it would be a trivial problem.
Any help would be greatly appreciated! Please ask more information, if you wish to help, but don't fully understand the issue.