I have a custom UITableView cell set up in my UITableView like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"CELL_IDENTIFIER";
SGCustomCell *cell = (SGCustomCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) cell = [[SGCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell = [self customizedCell:cell withPost:[postsArray objectAtIndex:indexPath.row]];
return cell;
}
I set up the cell like this (specifically setting the UITextView.text to nil - as noted in this answer):
descriptionLabel.text = nil;
descriptionLabel.text = post.postDescription;
descriptionLabel.frame = CGRectMake(leftMargin - 4, currentTitleLabel.frame.origin.y + currentTitleLabel.frame.size.height + 10, self.frame.size.width - topMargin * 3, 100);
[descriptionLabel sizeToFit];
The cells are 100% reusable and UITextView is inited like this (as you see, nothing special):
descriptionLabel = [[UITextView alloc] init];
descriptionLabel.font = [UIFont fontWithName:#"HelveticaNeue" size:11];
descriptionLabel.editable = NO;
descriptionLabel.scrollEnabled = NO;
descriptionLabel.dataDetectorTypes = UIDataDetectorTypeLink;
descriptionLabel.frame = CGRectMake(leftMargin, currentTitleLabel.frame.origin.y + currentTitleLabel.frame.size.height + 10, self.frame.size.width - topMargin * 3, 10);
[self addSubview:descriptionLabel];
But when the table has around 50 cells and when I scroll it fast I get the following crash:
Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
Which is absolutely ridiculous - I comment out this line - descriptionLabel.dataDetectorTypes = UIDataDetectorTypeLink; and the app stops crashing! I've spent hours trying to figure out what the problem was and now I simply get this.
Tested on iOS 7.0.3
The crash happens when two cells with data type are being dequeued while
using the same cell identifier.
It seems to be a bug in iOS, but Apple may have good reasons to implement it this way.
(memory wise)
And so the only 100% bullet proof solution is to provide a unique identifier for cells
containing data types.
This doesn't mean you will set a unique identifier to all cells in your table, of course,
as it will eat up too much memory and your table scroll will be really slow.
You can use NSDataDetector to determine if a matched type was found on your text,
and only then save the found object as the cell identifier, like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *row = [self.dataSource objectAtIndex:indexPath.row];
static NSDataDetector *detector = nil;
if (!detector)
{
NSError *error = NULL;
detector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber error:&error];
}
NSTextCheckingResult *firstDataType = [detector firstMatchInString:row
options:0
range:NSMakeRange(0, [row length])];
NSString *dataTypeIdentifier = #"0";
if (firstDataType)
{
if (firstDataType.resultType == NSTextCheckingTypeLink)
dataTypeIdentifier = [(NSURL *)[firstDataType URL] absoluteString];
else if (firstDataType.resultType == NSTextCheckingTypePhoneNumber)
dataTypeIdentifier = [firstDataType phoneNumber];
}
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell_%#", dataTypeIdentifier];
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
...
Note: Initializing NSDataDetector *detector as static
rather than initialize it for each cell improves performance.
I could reproduce your crash.
Implementing the following method within the TableViewCell subclass
- (void)prepareForReuse
{
[super prepareForReuse];
[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeNone];
}
and add following call within - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath before setting the text:
[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeLink];
worked for me. Maybe it cancels ongoing drawing inside the textview and is avoiding the crash that way.
edit: Calling [descriptionLabel setDataDetectorTypes: UIDataDetectorTypeNone]; and [descriptionLabel setDataDetectorTypes: UIDataDetectorTypeLink]; just before setting the text also seems to fix the crash
Providing you are using iOS6 or above, you can use an NSDataDetector to make an attributable string and use that as your TextView text. A modified version of the following method is what we are going to be using. The method takes a string and some already predefined attributes (like font and text color), and will stop after the 100th link. It has some problems multiple phone numbers, though. You need to define your own code for URL escapping the address. The the NSDataDetector bit was taken from Apple's NSDataDetector reference: https://developer.apple.com/librarY/mac/documentation/Foundation/Reference/NSDataDetector_Class/Reference/Reference.html
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:attributes];
__block NSUInteger count = 0;
if (!_dataDetector)
{
NSError *error = nil;
_dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeAddress | NSTextCheckingTypePhoneNumber | NSTextCheckingTypeLink
error:&error];
}
[_dataDetector enumerateMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
NSRange matchRange = [match range];
if ([match resultType] == NSTextCheckingTypeLink)
{
NSURL *url = [match URL];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
else if ([match resultType] == NSTextCheckingTypePhoneNumber)
{
NSString *phoneNumber = [NSString stringWithFormat:#"tel:%#",[match phoneNumber]];
NSURL *url = [NSURL URLWithString:phoneNumber];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
else if ([match resultType] == NSTextCheckingTypeAddress)
{
//Warning! You must URL escape this!
NSString *address = [string substringWithRange:matchRange];
//Warning! You must URL escape this!
NSString *urlString = [NSString stringWithFormat:#"http://maps.apple.com/?q=%#",address];
NSURL *url = [NSURL URLWithString:urlString];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
if (++count >= 100) *stop = YES;
}];
return attributedString;
Related
this is my code that shows data in table,my complete data is not showing in cell.
1st image is when i set scrollable to no ,2nd image when i do not set scrollable.i am a beginner.plz help me out of this.
- (void)textViewDidChange:(UITextView *)textView{
[table beginUpdates];
[table endUpdates];
}
-(void)createdatabase{
BOOL success;
NSFileManager *filemanager = [NSFileManager defaultManager];
success = [filemanager fileExistsAtPath:datapath];
if (success)return;
NSString *databasefromapp = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:dataname];
[filemanager copyItemAtPath:databasefromapp toPath:datapath error:nil];
}
-(void)getdatabase{
eventitleary = [[NSMutableArray alloc]init];
eventdescary = [[NSMutableArray alloc]init];
eventimgary = [[NSMutableArray alloc] init];
sqlite3 *dataname1;
if (sqlite3_open([datapath UTF8String],&dataname1) == SQLITE_OK) {
const char *sqlStatement;
sqlStatement = "SELECT * FROM photography_events";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(dataname1, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
// Read the data from the result row
NSString *str_title = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
[eventitleary addObject:str_title];
NSString *str_desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
[eventdescary addObject:str_desc];
NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement, 2) length:sqlite3_column_bytes(compiledStatement, 2)];
[eventimgary addObject:data];
}
}
}
NSLog(#"%#", eventitleary);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return eventitleary.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *cellidenti = #"CellIdenti";
TableViewCell2 *cell = (TableViewCell2*)[tableView dequeueReusableCellWithIdentifier:cellidenti];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle]loadNibNamed:#"TableViewCell2" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.eventitlelbl.text = [eventitleary objectAtIndex:indexPath.row];
cell.eventdesc.text = [eventdescary objectAtIndex:indexPath.row];
cell.eventdesc.editable = NO;
//cell.eventdesc.scrollEnabled = NO;
[cell.eventdesc sizeToFit];
frame = cell.eventdesc.frame;
frame.size = cell.eventdesc.contentSize;
cell.eventdesc.frame = frame;
NSData *dataimg = (NSData*)[eventimgary objectAtIndex:indexPath.row];
cell.eventimg.image = [UIImage imageWithData:dataimg];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
// Return the height with a bit of additional padding space
return frame.size.height + 300;
}
You can achieve this by adaptive layout. Check this awesome tutorial if you are working with autolayout. Else you can set dynamic tableView cell height by calculating the height in which your text will fit.
You can calculate height of text by using below method. Pass text, required font and width of your textview.
-(CGFloat)heightForText:(NSString*)text withFont:(UIFont *)font andWidth:(CGFloat)width
{
CGSize constrainedSize = CGSizeMake(width, MAXFLOAT);
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName,nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:text attributes:attributesDictionary];
CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
if (requiredHeight.size.width > width) {
requiredHeight = CGRectMake(0,0,width, requiredHeight.size.height);
}
return requiredHeight.size.height;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self heightForText:#"your text view text for this row" withFont:[UIFont fontWithName:#"Helvetica" size:16] andWidth:320];
}
i just got it, i wanted to do it dynamically rather than using auto layout,here is my code.Hope in future it works out to anyone.
I have an requirement like the UITableview row height has to increase dynamically when i add more data..Like
_quoteArray = [#[#"For the past 33 years, I have looked in the mirror every morning and asked myself: 'If today were the last day of my life, would I want to do what I am about to do today?' And whenever the answer has been 'No' for too many days in a row, I know I need to change something. -Steve Jobs",
#"Be a yardstick of quality. Some people aren't used to an environment where excellence is expected. - Steve Jobs",
#"Innovation distinguishes between a leader and a follower. -Steve Jobs"]];
I wrote the code like…..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"NotificationCell";
MyNotificationCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
//cell.dateLabel.text =dateDisplayStr;
cell.teacherChangeLabel.text = _quoteArray[quoteIndex];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Calculate a height based on a cell
static NSString *simpleTableIdentifier = #"NotificationCell";
MyNotificationCell *cell = [self.NotificationTableview dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(!cell) {
cell = [self.NotificationTableview dequeueReusableCellWithIdentifier:#"CustomCell"];
}
// Configure the cell
int quoteIndex = indexPath.row % [quoteArray count];
cell.teacherChangeLabel.text = quoteArray[quoteIndex];
// Layout the cell
[cell setNeedsLayout];
// Get the height for the cell
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
// Padding of 1 point (cell separator)
CGFloat separatorHeight = 1;
return height + separatorHeight;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 140;
}
But it is not increasing the row height if I add extra data.I don’t know where I did mistake.Can anyone please help me in this
If you want to change based on the size of the string just do it like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = [yourStringArray objectAtIndex:indexPath.row];
UIFont *font = theFontSizeYourWant;
return [self heigthWithString:text andFont:font]+30//put the +30 for personal like;
}
- (CGFloat)heigthWithString:(NSString*)string andFont:(UIFont *)font
{
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:string];
[attrStr addAttribute:NSFontAttributeName
value:font
range:NSMakeRange(0, [attrStr length])];
CGRect rect = [attrStr boundingRectWithSize:CGSizeMake(250, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
context:nil];
return rect.size.height;
}
Hope this helps!
Use
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Change the height of cell based on indexpath ForEg
if([indexPath row]==0){
return 44;
}
return 140;
}
to change the height of a cell.
If you need to support iOS7 and there are lots of items affecting the height.
As there are lots of items(or some dynamic size items), the height is not easy to calculate.
I would call a protocol method to update the height.
Pos:
Easy to change the height
No annoying calculation
Cons:
memory consumption
you may see the UITableView updating.
#property (strong, nonatomic) NSMutableArray *loadedCellHeight;
#pragma CellDelegate Methods
- (void)displayHeight:(NSString*)height atIndexPath:(NSIndexPath *)indexPath
{
NSPredicate *filter = [NSPredicate predicateWithFormat:#"indexPath == %#", indexPath];
NSArray *filteredArray = [self.loadedHeight filteredArrayUsingPredicate:filter];
if (filteredArray.count==0) {
[self.loadedAdHeight addObject:#{#"indexPath": indexPath, #"height": height}];
[self.tableView beginUpdates];
[self.tableView endUpdates];
} else {
NSDictionary *originalDict = filteredArray[0];
if ([[originalDict objectForKey:#"height"] floatValue] != [height floatValue]) {
[_loadedCellHeight removeObject:originalDict];
[_loadedCellHeight addObject:#{#"indexPath": indexPath, #"height": height}];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dict = [self.dataArray objectAtIndex:indexPath.row];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"indexPath == %#", indexPath];
NSArray *filteredArray = [self.loadedAdHeight filteredArrayUsingPredicate:filter];
if (filteredArray.count>0) {
return [filteredArray[0][#"height"] floatValue];
}
return 0;
}
What I did in my Cell(there is a webview inside it):
- (void)loadAd:(NSString*)path
{
if (_loaded) {
return;
}
NSString *encodeUrl = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
self.url = encodeUrl;
[self.webView setScalesPageToFit:YES];
self.webView.contentMode = UIViewContentModeScaleAspectFit;
self.webView.delegate = self;
self.webView.scrollView.bounces = NO;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:encodeUrl]];
[self.webView loadRequest:request];
}
-(void)parseHtml
{
NSString *html = [self.webView stringByEvaluatingJavaScriptFromString: #"document.body.innerHTML"];
NSLog(#"html:%#", html);
NSDictionary *dict = [NSDictionary dictionaryWithXMLString:html];
NSLog(#"parsed html:%#", [dict description]);
NSDictionary *heightDict = [dict dictionaryValueForKeyPath:#"img.hidden"];
NSLog(#"%#", [heightDict valueForKeyPath:#"_value"]);
NSString *heightStr = [heightDict valueForKeyPath:#"_value"];
NSString *height = [heightStr stringByReplacingOccurrencesOfString:#"advheight:" withString:#""] ;
if (self.delegate && !_loaded) {
[self.delegate displayHeight:height atIndexPath:_indexPath];
_loaded = YES;
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self parseHtml];
}
* I got it figured out thanks to Paulw11 and sjeohp comments. I was using the amount of text to change the cell height and didnt correct the objectAtIndex in that method when i changed to using the array over static text. *
I have a chat app that im trying to use a tableView to show the chat interaction. Im saving the "source" and the contents into an array and trying to get the tableview to reload that anytime a message is sent or received but it crashes everytime on the reloadData call.
In the ViewDidLoad:
chatLog = [[NSMutableArray alloc]init];
and then other methods:
-(IBAction)sendMessagePressed:(UIBarButtonItem *)sender {
NSLog(#"Send Pressed");
// if the message bar isnt blank send the message
if ( ![messageInputBar.text isEqualToString:#""] ) {
NSString* text = [NSString stringWithFormat:#"You Wrote:\n%#", messageInputBar.text];
NSString* source = #"self";
NSArray* sent = [[NSArray alloc]initWithObjects:source, text, nil];
messageInputBar.text = #"";
[self CloseMessageKeys];
[chatLog addObject:sent];
// this is where it crashes. this code was working with static text before
// i implemented the mutable array
[chatTable reloadData];
NSData* messageData = [messageInputBar.text dataUsingEncoding:NSUTF8StringEncoding];
NSArray* connectedPeers = _app_Delegate.mpc_Handler.mpc_session.connectedPeers;
NSError* error;
[_app_Delegate.mpc_Handler.mpc_session sendData:messageData toPeers:connectedPeers withMode:MCSessionSendDataReliable error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
This is the TableView cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ( [[[chatLog objectAtIndex:indexPath.row]objectAtIndex:0]isEqualToString:#"self"]) {
OutgoingTableViewCell* cell = [chatTable dequeueReusableCellWithIdentifier:#"outgoingCell" forIndexPath:indexPath];
NSString* text = [[chatLog objectAtIndex:indexPath.row]objectAtIndex:1];
cell.txtLabel.text = text;
[[cell txtLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell txtLabel] setLineBreakMode: NSLineBreakByWordWrapping];
[[cell txtLabel] setFont:[UIFont systemFontOfSize: 14.0]];
cell.backgroundColor = [UIColor greenColor];
[self showTheBottom];
return cell;
} else {
IncomingTableViewCell* cell = [chatTable dequeueReusableCellWithIdentifier:#"incomingCell" forIndexPath:indexPath];
NSString* text = [[chatLog objectAtIndex:indexPath.row]objectAtIndex:1];
cell.txtLabel.text = text;
[[cell txtLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell txtLabel] setLineBreakMode: NSLineBreakByWordWrapping];
[[cell txtLabel] setFont:[UIFont systemFontOfSize: 14.0]];
cell.backgroundColor = [UIColor blueColor];
[self showTheBottom];
return cell;
}
}
length is not a method on NSArray. Use [array count]
I got it figured out thanks to #Paulw11 and #sjeohp comments. I was using the amount of text to change the cell height and didnt correct the objectAtIndex in that method when i changed to using the array over static text. *
in another method I had:
NSAttributedString *aString = [NSAttributedString alloc] initWithString:[chatLog objectAtIndex:indexPath.row];
and it needed to be:
NSAttributedString *aString = [[NSAttributedString alloc] initWithString:[[chatLog objectAtIndex:indexPath.row]objectAtIndex:1]];
Thanks to #Paulw11 and #sjeohp for helping me figure out the exception breakpoint feature in Xcode
Your dequeueReusableCell code is fail. you need check if it nil then init cell. And check about numberOfRowsInSection code to return chatLog.count
I'm thinking that this is an issue with reusing cells but I can't figure this out and would appreciate some additional eyes on it. I have a uitableviewcell subclass that compares two values, if one value is higher it changes the cell background to red, else it changes it to white. As I scroll, some cells are white that should be red and vice versa.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
tut_MaintListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"maintCell" forIndexPath:indexPath];
// Configure the cell...
MaintItem *mItem = [self.fetchedResultsController objectAtIndexPath:indexPath];
[cell configureCellForEntry:mItem sendCar:self.carDetail];
return cell;
}
UITableViewCell Subclass
- (void)configureCellForEntry:(MaintItem *)mItem sendCar:(Car *)carDetails
{
self.itemLabel.text = [mItem valueForKey:#"item"];
self.actionLabel.text = [mItem valueForKey:#"action"];
self.engineLabel.text = [mItem valueForKey:#"engineCode"];
self.maintIDLabel.text = [[mItem valueForKey:#"maintID" ]stringValue];
// Grab the mileages recorded in the log for this maint item and turn it into a sorted array
NSArray *result = [[mItem.toLog valueForKey:#"mileage"] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"" ascending:YES]]];
// Determine mileage of next service
NSString *nextServiceMileage = [NSString stringWithFormat:#"%d", [mItem.intMileage intValue] + [[result lastObject] intValue]];
nextServiceMileageNS = #([nextServiceMileage intValue]);
if ([mItem.frequencyID isEqualToNumber:[NSNumber numberWithInt:3]])
{
NSString *timing = [[NSString alloc] initWithFormat:#" %# Once at %# miles or %# months", [mItem valueForKeyPath:#"frequencyID"], [mItem valueForKeyPath:#"intMileage"], [mItem valueForKeyPath:#"intMonth"]];
NSString *howOften = [[NSString alloc] initWithFormat:#" %#", timing];
self.howOftenLabel.text = howOften;
if (carDetails.mileage > nextServiceMileageNS)
{
self.backgroundColor = [UIColor redColor];
}
else
{
self.backgroundColor = [UIColor whiteColor];
}
}
else if ([mItem.frequencyID isEqualToNumber:[NSNumber numberWithInt:4]])
{
NSString *timing = [[NSString alloc] initWithFormat:#" %# Every %# miles or %# months, due at %# ", [mItem valueForKeyPath:#"frequencyID"], [mItem valueForKeyPath:#"intMileage"], [mItem valueForKeyPath:#"intMonth"], nextServiceMileage];
NSString *howOften = [[NSString alloc] initWithFormat:#" %#", timing];
self.howOftenLabel.text = howOften;
if (carDetails.mileage > nextServiceMileageNS)
{
self.backgroundColor = [UIColor redColor];
}
else
{
self.backgroundColor = [UIColor whiteColor];
}
}
else
{
NSString *howOften = [[NSString alloc] initWithFormat:#" %#", [mItem valueForKeyPath:#"frequencyID"]];
self.howOftenLabel.text = howOften;
}
}
The Solution is: you have to set the backgroundColor in the else part too. Better solution would be,
UIView *backgroundView;
if (condition_1) {
backgroundView = [UIView new];
[backgroundView setBackgroundColor:[UIColor whiteColor]];
} else if (condition_2) {
backgroundView = [UIView new];
[backgroundView setBackgroundColor:[UIColor redColor]];
} else {
// here you can set or leave it.
}
[self setBackgroundView:backgroundView];
hope it will work for you...
The solution was that I was comparing two NSnumber objects in the if statement. I changed
if (carDetails.mileage > nextServiceMileageNS)to if ([carDetails.mileage intvalue] > [nextServiceMileageNS intvalue]) and now it worked correctly. The way the random background were applied it seemed to be a cell reuse issue.
I'm currently using a UITextView in a UITableViewCell in order to make links clickable, but this is giving very poor performance.
So I was wondering if it's possible to detect links in a NSString and if there is a link, use the UITextView, otherwise just use a UILabel.
Absolutely. Use NSDataDetector (NSDataDetector Class Reference)
I guess you are familiar with regexes to detect URLs, so in order to get one or the other type of view in your cell, you can simply return two different UITableViewCells from your tableView:cellForRowAtIndexPath: method.
It could look like this (please notice, typed in the browser not tested):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *dataString = // Get your string from the data model
// Simple pattern found here: http://regexlib.com/Search.aspx?k=URL
NSString *URLpattern = #"^http\\://[a-zA-Z0-9\-\.]+\\.[a-zA-Z]{2,3}(/\\S*)?$";
NSError *error = NULL;
NSRegularExpression *URLregex = [NSRegularExpression regularExpressionWithPattern:URLpattern
options:NSRegularExpressionCaseInsensitive
error: &error];
NSUInteger numberOfMatches = [URLregex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
if ( numberOfMatches == 0 ) {
static NSString *PlainCellIdentifier = #"PlainCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}
cell.textLabel.text = timeZoneWrapper.localeName;
}
else {
static NSString *FancyCellIdentifier = #"FancyCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}
// Configure cell view with text view here
}
return cell;
}
Using this snip of code you would be able to find and get http url in UILable using NSDataDetector:
NSDataDetector* detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray* matches = [detector matchesInString:yourString options:0 range:NSMakeRange(0, [yourString. length])];
NSLog(#"%#",matches) ;
NSMutableAttributedString *MylabelAttributes =
[[NSMutableAttributedString alloc] initWithString:yourString];
for (int index = 0 ; index < matches.count; index ++) {
NSTextCheckingResult *textResult = [matches objectAtIndex : index];
NSTextCheckingType textResultType = textResult.resultType;
NSRange testRange = textResult.range;
NSURL *testUrl = textResult.URL ;}
After applying this code, you will be able to attribute your `UILabel` text:
[MylabelAttributes addAttribute:NSLinkAttributeName value:testUrl range: testRange];
[MylabelAttributes addAttribute:NSFontAttributeName
value:[UIFont boldSystemFontOfSize:7.0]range:NSMakeRange(0,yourString.length)];