Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

RD92

macrumors newbie
Original poster
Jul 16, 2007
4
0
Hi, I created an app that counts the lines in a text view. I got it to work like this:

- (void)awakeFromNib
{
string = [textView string];
unsigned numberOfLines;
unsigned index;
unsigned stringLength = [string length];
for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
{
index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
[textField setIntValue:numberOfLines + 1];
}
}

I put '+ 1' because, I don't know why, it starts from zero. It works perfectly except It just counts them once. If you modify the text view, the text field doesn't change. How can I make it to coninuously check for changes in the text view?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
You don't want to continuously check for changes: this will use a large amount of CPU (this solution is called polling and, in general, is something we try and avoid).

The better solution would be to have the text view tell you when there is a change and re-count then.

To do this set your instance as the delegate of the view. You then have a number of methods you could implement.

The textDidChange: method of NSText would work, although from memory this would only get called when editing ends (i.e. you select another control) so is probably not what you want.

A better method might be to implement - (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString. Remember to return YES from this! This should get called on all changes to the text.
 

Nutter

macrumors 6502
Mar 31, 2005
432
0
London, England
Also, a for loop isn't particularly suitable here. Try this:

Code:
unsigned numberOfLines = 0;
unsigned index = 0;
while (index < [[textView string] length])
{
	index = NSMaxRange([[textView string] lineRangeForRange:NSMakeRange(index, 0)]);
	++numberOfLines;
}
[textField setIntValue:numberOfLines];

(I know this wasn't part of your question, so sorry if this is unwelcome advice.)
 

Eraserhead

macrumors G4
Nov 3, 2005
10,434
12,250
UK
@RD I think you are wrong, I think textDidChange does get called every time you type a character, at least certainly one of the delegates of NSText or NSTextField does. I think textDidEndEditing only gets called when you end editing ;).


I'd love to help find which method but I changed my code to use bindings instead.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
@RD I think you are wrong, I think textDidChange does get called every time you type a character, at least certainly one of the delegates of NSText or NSTextField does. I think textDidEndEditing only gets called when you end editing ;).

In that case that would be great. I have distinct memories of it not being called on very character change in an NSTextField though. I could be thinking of another delegate method though.

The simplest thing would be to try it!

Another reason for suggesting the other method was that it tells you the range being effected and the new characters. So you could use this data to update the count without a full recount which could save a lot of CPU time on a very long document...
 

Eraserhead

macrumors G4
Nov 3, 2005
10,434
12,250
UK
Another reason for suggesting the other method was that it tells you the range being effected and the new characters. So you could use this data to update the count without a full recount which could save a lot of CPU time on a very long document...

True, it did seem to be very inefficient to do it my way.
 

RD92

macrumors newbie
Original poster
Jul 16, 2007
4
0
Ok, I switched to textDidChange:NSTextDidEndEditingNotification but I have no idea how to count only the characters that have been added. Here's my code:

Code:
- (void)textDidChange:NSTextDidEndEditingNotification
{
	linesString = [textView string];
	unsigned numberOfLines;
	unsigned index;
	unsigned stringLength = [linesString length];
	for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
	{
		index = NSMaxRange([linesString lineRangeForRange:NSMakeRange(index, 0)]);
		[linesField setIntValue:numberOfLines + 1];
	}
}
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
There's no need to update your text field every single time. Just do it once at the end. Also, isn't componentsSeparatedByString: a more simpler way to count the # of lines?

Edit: Use Nutter's code. Much easier to read and more efficient.
 

RD92

macrumors newbie
Original poster
Jul 16, 2007
4
0
Ok, thanks it worked perfectly. Just one more thing, how can I get the current line that the insertion point is in?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.