0

I'm trying to find every occurrence of a string in UITextView and attribute that occurrence but i attributes the entire textView after the first occurrence of that string. Is it possible to find the location of each occurrence of "hello" and attribute them without attributing the entire textView

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

            if textView == self.textView {

        let nsString = textView.text as NSString
        let end = textView.text.characters.count
        let range = NSMakeRange(0, end) as NSRange

        let hString = nsString.rangeOfString("hello")
        let text = NSMutableAttributedString(string: textView.text)

        let cTv = textView.attributedText.mutableCopy() as! NSMutableAttributedString


                if hString.length > 0{


           text.addAttribute(NSForegroundColorAttributeName, value: UIColor.magentaColor(), range: range)


                    cTv.replaceCharactersInRange(range, withAttributedString: text)

        }


                textView.attributedText = text

    }
    return true

}
jscs
  • 63,694
  • 13
  • 151
  • 195
JoanDoe
  • 13
  • 3

1 Answers1

2

The system sends textView(_:shouldChangeTextInRange:replacementText:) before it modifies textView.text. You would probably be better off implementing textViewDidChange(_:), which the system sends after it modifies textView.text.

func textViewDidChange(textView: UITextView) {
    let text = textView.text as NSString
    let richText = NSMutableAttributedString(string: text as String)
    var searchRange = NSMakeRange(0, text.length)
    while true {
        let range = text.rangeOfString("hello", options: [], range: searchRange)
        if range.location == NSNotFound {
            break
        }
        richText.addAttribute(NSForegroundColorAttributeName, value: UIColor.magentaColor(), range: range)
        searchRange.location = range.location + range.length
        searchRange.length = text.length - searchRange.location
    }
    textView.attributedText = richText
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • +1. This solves all the problems in the OPs code. One thing (possibly), depending on the string the OP searches for. As suggested in http://stackoverflow.com/questions/7033574/find-all-locations-of-substring-in-nsstring-not-just-first, adding 1 to the start of the search range makes sure that overlapping occurances of the string (if possible, depends on the string), are highlighted. – Linuxios Sep 22 '15 at 18:37
  • What's the stack trace? – rob mayoff Sep 22 '15 at 20:46
  • it cites "class AppDelegate: UIResponder, UIApplicationDelegate" – JoanDoe Sep 23 '15 at 18:29
  • and "libc++abi.dylib: terminating with uncaught exception of type NSException" – JoanDoe Sep 23 '15 at 19:43
  • I forgot to update `searchRange.location` in the loop. I've fixed my answer. – rob mayoff Sep 23 '15 at 21:10
  • Is it possible to use this with an array of Strings? I tried a for each loop inside the while loop but it never gets executed and the UITextView becomes disabled for some strange reason. – kye Nov 05 '15 at 16:27
  • You would need a for loop around the `while` loop and the initialization of `searchRange`. – rob mayoff Nov 05 '15 at 16:43