Cell with NSAttributedString makes the scrolling of UITableView slow - ios

I have a table view that contains multiple kinds of cells. One of them is a cell with a TextView and in this text view, I have to render an NSAttributedString from data. This has to be done on the main Thread according to Apple documentation:
The HTML importer should not be called from a background thread (that is, the options dictionary includes NSDocumentTypeDocumentAttribute with a value of NSHTMLTextDocumentType). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.
but rendering in this way will make lags on the scrolling of the table view and also will mess with auto layout. This is my code inside my cell.
dispatch_async(dispatch_get_main_queue(), ^{
NSString* htmlString = [NSString stringWithFormat:#"<div style=\"font-family:%#; font-size:%dpx; color:#08080d;\">%#</div>",fontNameBase, 16,txt];
htmlString = [Utility replaceHtmlCodeEntities:htmlString];
NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
self.textViewMsg.attributedText = txt;
});
I scroll my tableView like this:
-(void)reloadAndScroll{
[self.tableChat reloadData];
long lastRowNumber = [_tableChat numberOfRowsInSection:0] - 1;
if (lastRowNumber > 0) {
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
[_tableChat scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
}
Are there any other ways to create an Attributed string without these problems?

I think u have to create the Attributed String in your Model class, So that table view cell for row method does not create a new Attributed string on scrolling,Hope It well help you out, Thanks
+(AttributedModel *)methodToGetAttributedDetail :(NSString *)txt {
AttributedModel *objModel = [[AttributedModel alloc] init];
NSString* htmlString = [NSString stringWithFormat:#"<div style=\"font-family:%#; font-size:%dpx; color:#08080d;\">%#</div>",fontNameBase, 16,txt];
htmlString = [Utility replaceHtmlCodeEntities:htmlString];
NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
objModel.attributedString = attributedString;
return objModel;
}
Use this model value in CellforRow Method of table view

Related

iOS: The proper way to display Images and long texts with scroll functionality

I'm developing an app for a news website, i'm displaying the news articles using UITableView where each cell is an article title, when a user clicks on a cell (i.e an article), another view opens (using segue), now in this view i want to put the following:
The article's Image at the top.
The article's date under the image.
The article's description under the date. (Which could be very long)
The ability for the user to scroll the entire view. (not only the description)
NOTE: I have tried so many ways, i can't seem to know the proper way to implement this structure.
The modern solution is actually relatively simple: compose the whole thing as an attributed string and put it into a UITextView. The text view will automatically deal with the fact that the description may be very long, that all content should scroll together, etc.
E.g.
NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:
[[NSTextAttachment new] setImage:[UIImage imageNamed:#"whatever.png"]]];
... and use the natural means for composition of attributed strings and for setting things like font and colour on your other bits of text. Then just textView.attributedString = compoundString;.
Elaborated example:
- (void)setStory:(Story *)story
{
NSAttributedString *image = [story imageString];
NSAttributedString *date = [story dateString];
NSAttributedString *body = [story bodyString];
NSMutableAttributedString *wholeStory = [NSMutableAttributedString new];
// TODO: can you be sure image, date and body are all non-nil?
NSArray *allComponents = #[image, date, body];
for(NSAttributedString *component in allComponents)
{
[wholeStory appendAttributedString:component];
if(component != [allComponents lastObject])
[[wholeStory mutableString] appendString:#"\n\n"];
}
self.textView.attributedString = wholeStory;
}
... elsewhere, in the Story object ...
- (UIImage *)image
{
// ...something...
}
- (NSString *)dateText
{
// ...something, probably using NSDateFormatter unless it's returned
// from a server or wherever already formatted...
}
- (NSString *)bodyText
{
// ... something ...
}
- (NSAttributedString *)imageString
{
return [NSAttributedString attributedStringWithAttachment:
[[NSTextAttachment new] setImage:[self image]]];
}
- (NSAttributedString *)dateString
{
return [[NSAttributedString alloc]
initWithString:[self dateText]
attributes:
#{
NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleSubheadline],
... etc ...
}];
}
- (NSAttributedString *)bodyString
{
return [[NSAttributedString alloc]
initWithString:[self bodyText]
attributes:
#{
NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleBody],
... etc ...
}];
}
Check out the NSAttributedString UIKit Additions documentation for lists of the various attributes you can set other than NSFontAttributeName. Note that I've gone with the iOS 7+ way of asking for fonts by purpose rather than a specific size or font. That means that users who have turned up their default font size will get larger text in your app.
I have created a pod to programmatically add constraints. There is a special category for scrollViews, because they are so complicated to use with auto layout.
Here is the link to the project
There is an example app you can take a look at, but the things you would have to do would be
initialize your views (the image, date label and description label).
add the scrollView
add the subviews of the scrollView
UIScrollView *scrollView = [[UIScrollView alloc] init];
[self.view addSubview:scrollView];
[scrollView addConstraintsToFillHorizontal];
[scrollView addConstraintsToFillVertical];
[scrollView addConstraintsToAlignVerticalAllViews:#[image, dateLabel, descriptionLabel]];
This should be pretty simple to implement, but if you need more help, just let me know and I could provide you with some more sample code.
Good luck with your project!
Another way would be to display each article as a HTML string in a UIWebView.
NSURL *url = [NSURL URLWithString:self.articleController.url];
NSString *html = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL];
[self.articleView.webView loadHTMLString:html baseURL:baseURL];

NSArray with UI objects (Performance)

I have a NSArray (actually is a mutable array) with a UIWebView object in each index. I use this array to populate cell in a UITableView. I use a for loop to initialize each object in the array as following:
for (int i = 0; i < [self.events count]; i++) {
[self.uiWebViewArray addObject:[[UIWebView alloc] init]];
[[self.uiWebViewArray objectAtIndex:i] setUserInteractionEnabled:NO];
[[self.uiWebViewArray objectAtIndex:i] loadHTMLString:HTMLContent baseURL:nil];
}
At this point I am not populating the UITableViewCells yet.
Although it works, I think that it a terrible approach. Performance goes down when I increase the number of cell. At some point, it is possible to the user note the latency.
I also tried to populate each cell directly with a UIWebView but it is basically the same thing.
Does anyone have a suggestion to solve the problem of populate UITableViewCell with UIWebView objects in a efficient way?
A really appreciate any help.
The problem is not the array, is the webview that is really slow and memory hugry.
If you want to display HTML text with basic CSS and you are deploying >= iOS7, you should use NSAttributeString and that method:
NSDictionary *importParams = #{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding) };
NSError *error = nil;
NSData *stringData = [HTML dataUsingEncoding:NSUTF8StringEncoding] ;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:stringData options:importParams documentAttributes:NULL error:&error];
Or you can use third party libraries DTCoreText is one of them.
I think using a custom cell with a Web View inside it will be the better. Although whole concept of Web View inside a table view is weird.
Inside cellForRowAtIndexPath you would need to do something like:
[cell.webView loadHTMLString:HTMLContent baseURL:nil];
The main advantage of Table View is that the number of actual UITableViewCell instances created in memory are far less than total number of logical cells/rows. Actually, in usual cases Table View only creates cells needed to fill the frame, plus few extra.
So using custom table view cell with Web View inside is way better approach memory wise, but as I said whole idea is a bit weird.

AutoLayout row height miscalculating for NSAttributedString

My app pulls HTML from an API, converts it into a NSAttributedString (in order to allow for tappable links) and writes it to a row in an AutoLayout table. Trouble is, any time I invoke this type of cell, the height is miscalculated and the content is cut off. I have tried different implementations of row height calculations, none of which work correctly.
How can I accurately, and dynamically, calculate the height of one of these rows, while still maintaining the ability to tap HTML links?
Example of undesired behavior
My code is below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch(indexPath.section) {
...
case kContent:
{
FlexibleTextViewTableViewCell* cell = (FlexibleTextViewTableViewCell*)[TableFactory getCellForIdentifier:#"content" cellClass:FlexibleTextViewTableViewCell.class forTable:tableView withStyle:UITableViewCellStyleDefault];
[self configureContentCellForIndexPath:cell atIndexPath:indexPath];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.desc.font = [UIFont fontWithName:[StringFactory defaultFontType] size:14.0f];
return cell;
}
...
default:
return nil;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UIFont *contentFont = [UIFont fontWithName:[StringFactory defaultFontType] size:14.0f];
switch(indexPath.section) {
...
case kContent:
return [self textViewHeightForAttributedText:[self convertHTMLtoAttributedString:myHTMLString] andFont:contentFont andWidth:self.tappableCell.width];
break;
...
default:
return 0.0f;
}
}
-(NSAttributedString*) convertHTMLtoAttributedString: (NSString *) html {
return [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding]
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)}
documentAttributes:nil
error:nil];
}
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andFont:(UIFont *)font andWidth:(CGFloat)width {
NSMutableAttributedString *mutableText = [[NSMutableAttributedString alloc] initWithAttributedString:text];
[mutableText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, text.length)];
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:mutableText];
CGSize size = [self text:mutableText.string sizeWithFont:font constrainedToSize:CGSizeMake(width,FLT_MAX)];
CGSize sizeThatFits = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return sizeThatFits.height;
}
In the app I'm working on, the app pulls terrible HTML strings from a lousy API written by other people and converts HTML strings to NSAttributedString objects. I have no choice but to use this lousy API. Very sad. Anyone who has to parse terrible HTML string knows my pain. I use Text Kit. Here is how:
parse html string to get DOM object. I use libxml with a light wrapper, hpple. This combination is super fast and easy to use. Strongly recommended.
traverse the DOM object recursively to construct NSAttributedString object, use custom attribute to mark links, use NSTextAttachment to mark images. I call it rich text.
create or reuse primary Text Kit objects. i.e. NSLayoutManager, NSTextStorage, NSTextContainer. Hook them up after allocation.
layout process
Pass the rich text constructed in step 2 to the NSTextStorage object in step 3. with [NSTextStorage setAttributedString:]
use method [NSLayoutManager ensureLayoutForTextContainer:] to force layout to happen
calculate the frame needed to draw the rich text with method [NSLayoutManager usedRectForTextContainer:]. Add padding or margin if needed.
rendering process
return the height calculated in step 5 in [tableView: heightForRowAtIndexPath:]
draw the rich text in step 2 with [NSLayoutManager drawGlyphsForGlyphRange:atPoint:]. I use off-screen drawing technique here so the result is an UIImage object.
use an UIImageView to render the final result image. Or pass the result image object to the contents property of layer property of contentView property of UITableViewCell object in [tableView:cellForRowAtIndexPath:].
event handling
capture touch event. I use a tap gesture recognizer attached with the table view.
get the location of touch event. Use this location to check if user tapped a link or an image with [NSLayoutManager glyphIndexForPoint:inTextContainer:fractionOfDistanceThroughGlyph] and [NSAttributedString attribute:atIndex:effectiveRange:].
Event handling code snippet:
CGPoint location = [tap locationInView:self.tableView];
// tap is a tap gesture recognizer
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
if (!indexPath) {
return;
}
CustomDataModel *post = [self getPostWithIndexPath:indexPath];
// CustomDataModel is a subclass of NSObject class.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
location = [tap locationInView:cell.contentView];
// the rich text is drawn into a bitmap context and rendered with
// cell.contentView.layer.contents
// The `Text Kit` objects can be accessed with the model object.
NSUInteger index = [post.layoutManager
glyphIndexForPoint:location
inTextContainer:post.textContainer
fractionOfDistanceThroughGlyph:NULL];
CustomLinkAttribute *link = [post.content.richText
attribute:CustomLinkAttributeName
atIndex:index
effectiveRange:NULL];
// CustomLinkAttributeName is a string constant defined in other file
// CustomLinkAttribute is a subclass of NSObject class. The instance of
// this class contains information of a link
if (link) {
// handle tap on link
}
// same technique can be used to handle tap on image
This approach is much faster and more customizable than [NSAttributedString initWithData:options:documentAttributes:error:] when rendering same html string. Even without profiling I can tell the Text Kit approach is faster. It's very fast and satisfying even though I have to parse html and construct attributed string myself. The NSDocumentTypeDocumentAttribute approach is too slow thus is not acceptable. With Text Kit, I can also create complex layout like text block with variable indentation, border, any-depth nested text block, etc. But it does need to write more code to construct NSAttributedString and to control layout process. I don't know how to calculate the bounding rect of an attributed string created with NSDocumentTypeDocumentAttribute. I believe attributed strings created with NSDocumentTypeDocumentAttribute are handled by Web Kit instead of Text Kit. Thus is not meant for variable height table view cells.
EDIT:
If you must use NSDocumentTypeDocumentAttribute, I think you have to figure out how the layout process happens. Maybe you can set some breakpoints to see what object is responsible for layout process. Then maybe you can query that object or use another approach to simulate the layout process to get the layout information. Some people use an ad-hoc cell or a UITextView object to calculate height which I think is not a good solution. Because in this way, the app has to layout the same chunk of text at least twice. Whether you know or not, somewhere in your app, some object has to layout the text just so you can get information of layout like bounding rect. Since you mentioned NSAttributedString class, the best solution is Text Kit after iOS 7. Or Core Text if your app is targeted on earlier iOS version.
I strongly recommend Text Kit because in this way, for every html string pulled from API, the layout process only happens once and layout information like bounding rect and positions of every glyph are cached by NSLayoutManager object. As long as the Text Kit objects are kept, you can always reuse them. This is extremely efficient when using table view to render arbitrary length text because text are laid out only once and drawn every time a cell is needed to display. I also recommend use Text Kit without UITextView as the official apple docs suggested. Because one must cache every UITextView if he wants to reuse the Text Kit objects attached with that UITextView. Attach Text Kit objects to model objects like I do and only update NSTextStorage and force NSLayoutManager to layout when a new html string is pulled from API. If the number of rows of table view is fixed, one can also use a fixed list of placeholder model objects to avoid repeat allocation and configuration. And because drawRect: causes Core Animation to create useless backing bitmap which must be avoided, do not use UIView and drawRect:. Either use CALayer drawing technique or draw text into a bitmap context. I use the latter approach because that can be done in a background thread with GCD, thus the main thread is free to respond to user's operation. The result in my app is really satisfying, it's fast, the typesetting is nice, the scrolling of table view is very smooth (60 fps) since all the drawing process are done in background threads with GCD. Every app needs to draw some text with table view should use Text Kit.
You need to update intrinsic content size.
I assume that you set attributed text to label in this code [self configureContentCellForIndexPath:cell atIndexPath:indexPath];
So, it should look like this
cell.youLabel.attributedText = NSAttributedString(...)
cell.youLabel.invalidateIntrinsicContentSize()
cell.youLabel.layoutIfNeeded()
You height calculation code (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andFont:(UIFont *)font andWidth:(CGFloat)width should be replaced with cell height calculation using prototyping cell.
I'm assuming you are using a UILabel to display the string?
If you are, I have had countless issues with multiline labels with autoLayout. I provided an answer here
Table View Cell AutoLayout in iOS8
which also references another answer of mine that has a breakdown of how i've solved all my issues. Similar issues have cropped up again in iOS 8 that require a similar fix in a different area.
All comes down to the idea of setting the UILabel's preferredMaxLayoutWidth every time is bounds change. What also helped is setting the cells width to be the width of the tableview before running:
CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
I ran into a very similar issue on another project where fields using NSAttributedString weren't rendering with the correct height. Unfortunately, there are two bugs with it that made us completely drop using it in our project.
The first is a bug that you've noticed here, where some HTML will cause an incorrect size calculation. This is usually from the space between the p tags. Injecting CSS sort of solved the issue, but we had no control over the incoming format. This behaves differently between iOS7 and iOS8 where it's wrong on one and right on the other.
The second (and more serious) bug is that NSAttributedString is absurdly slow in iOS 8. I outlined it here: NSAttributedString performance is worse under iOS 8
Rather than making a bunch of hacks to have everything perform as we wanted, the suggestion of using https://github.com/Cocoanetics/DTCoreText worked out really well for the project.
If you can target iOS 8 using dynamic cell sizing is the ideal solution to your problem.
To use dynamic cell sizing, delete heightForRowAtIndexPath: and set self.tableView.rowHeight to UITableViewAutomaticDimension.
Here is a video with more details:
https://developer.apple.com/videos/wwdc/2014/?include=226#226
You can replace this method to calculate the height of attributed string:
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andFont:(UIFont *)font andWidth:(CGFloat)width {
CGFloat result = font.pointSize + 4;
if (text)
result = (ceilf(CGRectGetHeight([text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil])) + 1);
return result;
}
Maybe the font you changed doesnt matches with the font of content on html pages. So, use this method to create attributed string with appropriate font:
// HTML -> NSAttributedString
-(NSAttributedString*) convertHTMLtoAttributedString: (NSString *) html {
NSError *error;
NSDictionary *options = #{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:nil error:&error];
if(!attrString) {
NSLog(#"creating attributed string from HTML failed: %#", error.debugDescription);
}
return attrString;
}
// force font thrugh & css
- (NSAttributedString *)attributedStringFromHTML:(NSString *)html withFont:(UIFont *)font {
return [self convertHTMLtoAttributedString:[NSString stringWithFormat:#"<span style=\"font-family: %#; font-size: %f\";>%#</span>", font.fontName, font.pointSize, html]];
}
and in your tableView:heightForRowAtIndexPath: replace it with this:
case kContent:
return [self textViewHeightForAttributedText:[self attributedStringFromHTML:myHTMLString withFont:contentFont] andFont:contentFont andWidth:self.tappableCell.width];
break;
You should be able to convert to an NSString to calculate the height like this.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIFont * font = [UIFont systemFontOfSize:15.0f];
NSString *text = [getYourAttributedTextArray objectAtIndex:indexPath.row] string];
CGFloat height = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, maxHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:#{NSFontAttributeName: font} context:nil].size.height;
return height + additionalHeightBuffer;
}
[cell.descriptionLabel setPreferredMaxLayoutWidth:375.0];

Voice over only reads UILabels and not UIWebview content

I have created UITableViewCell, that contains 2 objects:
UILabel - Used to show title text.
UIWebView- Used to show HTML.
Normally when Voice focus UITableViewCell, it read all added labels without any problem, but in my case, voice over only reads title and not the webview html content, user has to swipe right and left to move to next/previous element to read the content of webview.
My requirement is that when voice focus UITableViewCell, voice should read UILabels and webview content in one go, because as a developer we know its a HTML, but for app user(blind)
doesn't have any idea about it.
Also I want to know that how to disable UIWebview accessibility. I tried by setting isAccessibility to NO, but still Voice Over focus UIWebview.
[self.webview setIsAccessibilityElement:NO];
How to solve this problem?
I have resolved this problem by implementing method "accessibilityLabel" inside table cell view. For webview fetch web view content, convert html into plain text and use it. Don't forget to disable label and webview accessibility.
-(NSString*)accessibilityLabel{
NSString *labelText=nil;
NSMutableString *cellLabelText=[[NSMutableString alloc] init];
//Set label
[cellLabelText appendString:[NSString stringWithFormat:#", %#", self.titleLabel.text]];
//Fetch web view content, convert html into plain text and use it.
NSString *html = [self stringByEvaluatingJavaScriptFromString: #"document.body.innerHTML"];
NSString *plainText=[self convertHTMLIntoPlainText:html];
[cellLabelText appendString:plainText];
labelText=[NSString stringWithString:cellLabelText];
[cellLabelText release];
return labelText;
}
-(NSString *)convertHTMLIntoPlainText:(NSString *)html{
NSScanner *myScanner;
NSString *text = nil;
myScanner = [NSScanner scannerWithString:html];
while ([myScanner isAtEnd] == NO) {
[myScanner scanUpToString:#"<" intoString:NULL] ;
[myScanner scanUpToString:#">" intoString:&text] ;
html = [html stringByReplacingOccurrencesOfString:[NSString stringWithFormat:#"%#>", text] withString:#""];
}
//
html = [html stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return html;
}
How about:
[self.webview setAccessibilityElementHidden:YES]
Then set whatever accessibility label you like on the cell with the accessibilityLabel property.

Change size of text in UITextView based on content of NSString

I am trying to load a UITextView with content from instances of a NSManagedObject subclass (verses in a Bible reader app).
My UITextView is loaded by iterating through the verses in a selected chapter and appending each consecutive verse.
NSArray *selectedVerses = [[Store sharedStore] versesForBookName:selectedBook
ChapterNumber:selectedChapterNum];
displayString = #"";
for (Verse *v in selectedVerses) {
NSMutableString *addedString =
[NSMutableString stringWithFormat:#"%d %#", [v versenum], [v verse]];
displayString = [NSMutableString stringWithFormat:#"%# %#", addedString, displayString];
}
NSString *title = [NSString stringWithFormat:#"%# %#", selectedBook, selectedChapter];
[self setTitle:title];
[[self readerTextView] setNeedsDisplay];
[[self readerTextView] setText:displayString];
The above code generates the correct view, but only allows for one size of text for the entire UITextView.
I would like to have the verse number that precedes each verse to be a smaller size font than its verse, but have not found a way to make it work. I've been reading through the documentation, and it seems that this should be possible with TextKit and CoreText through the use of attributed strings, but I can't seem to get this to compile.
I do not want to load the view as a UIWebView.
Any suggestions for this are greatly appreciated.
You're looking for NSAttributedString and NSMutableAttributedString. You should read Introduction to Attributed String Programming Guide. They're generally like normal strings, but additionally contain attributes with ranges to which they apply. One more method that would be helpful to you is:
[self readerTextView].attributedText = yourAttributedString;
If you have some specific problems with attributed strings, please post your code.

Resources