Suggest # tags while typing (like Twitter) for iPhone UITextView












4















I'd building an app that uses hashtags, like Twitter or Tweetbot. When you're typing a message, if you type the hashtag symbol, I'd like to suggest tags that match the current one you're typing.



I've already figured out how to get the UITableView to appear and show a list of hashtags, but what I can't figure out is how to do the following:




  1. Get the NSRange of the current word being typed,

  2. See if that range is formatted like a hashtag (NSRegularExpression @"#\w\w*")

  3. (From here on out, I've got the code figured out to search for matching hashtags and show them in the UITableView)


Can anyone help me with steps 1 and 2? I've been thinking about using textViewDidChange:, but I'm concerned that the app's performance might suffer if I'm constantly running methods every time the characters change.



Thanks!










share|improve this question





























    4















    I'd building an app that uses hashtags, like Twitter or Tweetbot. When you're typing a message, if you type the hashtag symbol, I'd like to suggest tags that match the current one you're typing.



    I've already figured out how to get the UITableView to appear and show a list of hashtags, but what I can't figure out is how to do the following:




    1. Get the NSRange of the current word being typed,

    2. See if that range is formatted like a hashtag (NSRegularExpression @"#\w\w*")

    3. (From here on out, I've got the code figured out to search for matching hashtags and show them in the UITableView)


    Can anyone help me with steps 1 and 2? I've been thinking about using textViewDidChange:, but I'm concerned that the app's performance might suffer if I'm constantly running methods every time the characters change.



    Thanks!










    share|improve this question



























      4












      4








      4


      9






      I'd building an app that uses hashtags, like Twitter or Tweetbot. When you're typing a message, if you type the hashtag symbol, I'd like to suggest tags that match the current one you're typing.



      I've already figured out how to get the UITableView to appear and show a list of hashtags, but what I can't figure out is how to do the following:




      1. Get the NSRange of the current word being typed,

      2. See if that range is formatted like a hashtag (NSRegularExpression @"#\w\w*")

      3. (From here on out, I've got the code figured out to search for matching hashtags and show them in the UITableView)


      Can anyone help me with steps 1 and 2? I've been thinking about using textViewDidChange:, but I'm concerned that the app's performance might suffer if I'm constantly running methods every time the characters change.



      Thanks!










      share|improve this question
















      I'd building an app that uses hashtags, like Twitter or Tweetbot. When you're typing a message, if you type the hashtag symbol, I'd like to suggest tags that match the current one you're typing.



      I've already figured out how to get the UITableView to appear and show a list of hashtags, but what I can't figure out is how to do the following:




      1. Get the NSRange of the current word being typed,

      2. See if that range is formatted like a hashtag (NSRegularExpression @"#\w\w*")

      3. (From here on out, I've got the code figured out to search for matching hashtags and show them in the UITableView)


      Can anyone help me with steps 1 and 2? I've been thinking about using textViewDidChange:, but I'm concerned that the app's performance might suffer if I'm constantly running methods every time the characters change.



      Thanks!







      iphone ios regex uitextview nsregularexpression






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jun 29 '13 at 16:51









      Alan Moore

      60.8k979132




      60.8k979132










      asked Nov 26 '11 at 19:46









      bryanjclarkbryanjclark

      4,01512558




      4,01512558
























          2 Answers
          2






          active

          oldest

          votes


















          6














          I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.



          To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.



          Here's the code:



          //Get the ranges of current hashtags
          NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
          NSTextCheckingResult *currentHashtag;

          if ([hashtagRanges count] >0)
          {
          //List the ranges of all the hashtags
          for (int i = 0; i<[hashtagRanges count]; i++)
          {
          NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
          //Check if the currentRange intersects the hashtag
          //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
          NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
          if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
          {
          //If the cursor is over the hashtag, then snag that hashtag for matching purposes.
          currentHashtag = hashtag;
          }
          }

          if (currentHashtag){
          //If we found one hashtag that we're currently editing

          //Display the hashtag suggester, feed it the current hashtag for matching.
          [self showTagTable];

          //Get the current list of hashtags into an array
          NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
          NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags"
          inManagedObjectContext:self.note.managedObjectContext];
          [hashtagRequest setEntity:tagEntityDescription];
          NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed"
          ascending:YES];
          NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
          [hashtagRequest setSortDescriptors:sortDescriptors];

          NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]];
          [hashtagRequest setPredicate:tagPredicate];

          tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
          [tagListTable reloadData];

          //If there are no matching hashtags, then let's hide the tag table.
          if ([tagsToDisplay count] == 0)
          {
          [self hideTagTable];
          return;
          }

          }


          The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:



              #pragma mark - Hashtag Methods
          +(NSArray *)rangesOfHashtagsInString:(NSString *)string {
          NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
          options:NSRegularExpressionCaseInsensitive
          error:nil];
          NSArray *hashtagRanges = [hashtagDetector matchesInString:string
          options:NSMatchingWithoutAnchoringBounds
          range:NSMakeRange(0, string.length)];
          return hashtagRanges;
          }

          +(NSUInteger)numberOfHashtagsInString:(NSString *)string {
          NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
          options:NSRegularExpressionCaseInsensitive
          error:nil];
          NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
          options:NSRegularExpressionCaseInsensitive
          range:NSMakeRange(0, string.length)];
          return numberOfHashtags;
          }





          share|improve this answer


























          • This works great! Awesome code!!

            – Kevin van Mierlo
            Jan 6 '14 at 16:20











          • Thanks very much! :)

            – bryanjclark
            Jan 6 '14 at 19:18











          • I tried, but some of the error occured, Can you send this sample

            – SBM
            Sep 16 '15 at 11:13



















          3














          Another way I figured out to do this is as follows.



          In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.



          if ([text isEqualToString:@"#"]) {
          recordingHashTag = YES;
          startParse = range.location;

          }else if ([text isEqualToString:@" "]) {
          currentHashTag = nil;
          recordingHashTag = NO;
          theTable.hidden = YES;

          }

          if (recordingHashTag == YES) {
          NSString *value;
          if (startParse > [textView.text length] - startParse) {
          value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
          [self filterHashTagTableWithHash:value];
          }
          }


          If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.



          -(void)filterHashTagTableWithHash:(NSString *)hash{

          [self.filterHashTagArray removeAllObjects];

          for (NSString *hashTag in self.hashTagArray ){
          NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
          if (result.location != NSNotFound) {
          [filterHashTagArray addObject:hashTag];
          }
          }
          if (filterHashTagArray.count) {
          theTable.hidden = NO;
          }else{
          theTable.hidden = YES;
          }

          [self.theTable reloadData];
          }


          The final step is to insert the hash tag when the user clicks on the entry in the table.



              - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
          UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];

          NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
          textViewComment.text = newString;
          }


          Just don't forget to clear out your variables when a user backspaces mid hash tag.






          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8281098%2fsuggest-tags-while-typing-like-twitter-for-iphone-uitextview%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            6














            I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.



            To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.



            Here's the code:



            //Get the ranges of current hashtags
            NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
            NSTextCheckingResult *currentHashtag;

            if ([hashtagRanges count] >0)
            {
            //List the ranges of all the hashtags
            for (int i = 0; i<[hashtagRanges count]; i++)
            {
            NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
            //Check if the currentRange intersects the hashtag
            //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
            NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
            if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
            {
            //If the cursor is over the hashtag, then snag that hashtag for matching purposes.
            currentHashtag = hashtag;
            }
            }

            if (currentHashtag){
            //If we found one hashtag that we're currently editing

            //Display the hashtag suggester, feed it the current hashtag for matching.
            [self showTagTable];

            //Get the current list of hashtags into an array
            NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags"
            inManagedObjectContext:self.note.managedObjectContext];
            [hashtagRequest setEntity:tagEntityDescription];
            NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed"
            ascending:YES];
            NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
            [hashtagRequest setSortDescriptors:sortDescriptors];

            NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]];
            [hashtagRequest setPredicate:tagPredicate];

            tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
            [tagListTable reloadData];

            //If there are no matching hashtags, then let's hide the tag table.
            if ([tagsToDisplay count] == 0)
            {
            [self hideTagTable];
            return;
            }

            }


            The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:



                #pragma mark - Hashtag Methods
            +(NSArray *)rangesOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSArray *hashtagRanges = [hashtagDetector matchesInString:string
            options:NSMatchingWithoutAnchoringBounds
            range:NSMakeRange(0, string.length)];
            return hashtagRanges;
            }

            +(NSUInteger)numberOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
            options:NSRegularExpressionCaseInsensitive
            range:NSMakeRange(0, string.length)];
            return numberOfHashtags;
            }





            share|improve this answer


























            • This works great! Awesome code!!

              – Kevin van Mierlo
              Jan 6 '14 at 16:20











            • Thanks very much! :)

              – bryanjclark
              Jan 6 '14 at 19:18











            • I tried, but some of the error occured, Can you send this sample

              – SBM
              Sep 16 '15 at 11:13
















            6














            I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.



            To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.



            Here's the code:



            //Get the ranges of current hashtags
            NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
            NSTextCheckingResult *currentHashtag;

            if ([hashtagRanges count] >0)
            {
            //List the ranges of all the hashtags
            for (int i = 0; i<[hashtagRanges count]; i++)
            {
            NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
            //Check if the currentRange intersects the hashtag
            //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
            NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
            if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
            {
            //If the cursor is over the hashtag, then snag that hashtag for matching purposes.
            currentHashtag = hashtag;
            }
            }

            if (currentHashtag){
            //If we found one hashtag that we're currently editing

            //Display the hashtag suggester, feed it the current hashtag for matching.
            [self showTagTable];

            //Get the current list of hashtags into an array
            NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags"
            inManagedObjectContext:self.note.managedObjectContext];
            [hashtagRequest setEntity:tagEntityDescription];
            NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed"
            ascending:YES];
            NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
            [hashtagRequest setSortDescriptors:sortDescriptors];

            NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]];
            [hashtagRequest setPredicate:tagPredicate];

            tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
            [tagListTable reloadData];

            //If there are no matching hashtags, then let's hide the tag table.
            if ([tagsToDisplay count] == 0)
            {
            [self hideTagTable];
            return;
            }

            }


            The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:



                #pragma mark - Hashtag Methods
            +(NSArray *)rangesOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSArray *hashtagRanges = [hashtagDetector matchesInString:string
            options:NSMatchingWithoutAnchoringBounds
            range:NSMakeRange(0, string.length)];
            return hashtagRanges;
            }

            +(NSUInteger)numberOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
            options:NSRegularExpressionCaseInsensitive
            range:NSMakeRange(0, string.length)];
            return numberOfHashtags;
            }





            share|improve this answer


























            • This works great! Awesome code!!

              – Kevin van Mierlo
              Jan 6 '14 at 16:20











            • Thanks very much! :)

              – bryanjclark
              Jan 6 '14 at 19:18











            • I tried, but some of the error occured, Can you send this sample

              – SBM
              Sep 16 '15 at 11:13














            6












            6








            6







            I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.



            To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.



            Here's the code:



            //Get the ranges of current hashtags
            NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
            NSTextCheckingResult *currentHashtag;

            if ([hashtagRanges count] >0)
            {
            //List the ranges of all the hashtags
            for (int i = 0; i<[hashtagRanges count]; i++)
            {
            NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
            //Check if the currentRange intersects the hashtag
            //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
            NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
            if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
            {
            //If the cursor is over the hashtag, then snag that hashtag for matching purposes.
            currentHashtag = hashtag;
            }
            }

            if (currentHashtag){
            //If we found one hashtag that we're currently editing

            //Display the hashtag suggester, feed it the current hashtag for matching.
            [self showTagTable];

            //Get the current list of hashtags into an array
            NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags"
            inManagedObjectContext:self.note.managedObjectContext];
            [hashtagRequest setEntity:tagEntityDescription];
            NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed"
            ascending:YES];
            NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
            [hashtagRequest setSortDescriptors:sortDescriptors];

            NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]];
            [hashtagRequest setPredicate:tagPredicate];

            tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
            [tagListTable reloadData];

            //If there are no matching hashtags, then let's hide the tag table.
            if ([tagsToDisplay count] == 0)
            {
            [self hideTagTable];
            return;
            }

            }


            The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:



                #pragma mark - Hashtag Methods
            +(NSArray *)rangesOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSArray *hashtagRanges = [hashtagDetector matchesInString:string
            options:NSMatchingWithoutAnchoringBounds
            range:NSMakeRange(0, string.length)];
            return hashtagRanges;
            }

            +(NSUInteger)numberOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
            options:NSRegularExpressionCaseInsensitive
            range:NSMakeRange(0, string.length)];
            return numberOfHashtags;
            }





            share|improve this answer















            I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.



            To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.



            Here's the code:



            //Get the ranges of current hashtags
            NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
            NSTextCheckingResult *currentHashtag;

            if ([hashtagRanges count] >0)
            {
            //List the ranges of all the hashtags
            for (int i = 0; i<[hashtagRanges count]; i++)
            {
            NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
            //Check if the currentRange intersects the hashtag
            //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
            NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
            if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
            {
            //If the cursor is over the hashtag, then snag that hashtag for matching purposes.
            currentHashtag = hashtag;
            }
            }

            if (currentHashtag){
            //If we found one hashtag that we're currently editing

            //Display the hashtag suggester, feed it the current hashtag for matching.
            [self showTagTable];

            //Get the current list of hashtags into an array
            NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags"
            inManagedObjectContext:self.note.managedObjectContext];
            [hashtagRequest setEntity:tagEntityDescription];
            NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed"
            ascending:YES];
            NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
            [hashtagRequest setSortDescriptors:sortDescriptors];

            NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]];
            [hashtagRequest setPredicate:tagPredicate];

            tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
            [tagListTable reloadData];

            //If there are no matching hashtags, then let's hide the tag table.
            if ([tagsToDisplay count] == 0)
            {
            [self hideTagTable];
            return;
            }

            }


            The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:



                #pragma mark - Hashtag Methods
            +(NSArray *)rangesOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSArray *hashtagRanges = [hashtagDetector matchesInString:string
            options:NSMatchingWithoutAnchoringBounds
            range:NSMakeRange(0, string.length)];
            return hashtagRanges;
            }

            +(NSUInteger)numberOfHashtagsInString:(NSString *)string {
            NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\w\w*"
            options:NSRegularExpressionCaseInsensitive
            error:nil];
            NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
            options:NSRegularExpressionCaseInsensitive
            range:NSMakeRange(0, string.length)];
            return numberOfHashtags;
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 15 '14 at 15:01









            rihe

            1,18832047




            1,18832047










            answered Dec 3 '11 at 21:51









            bryanjclarkbryanjclark

            4,01512558




            4,01512558













            • This works great! Awesome code!!

              – Kevin van Mierlo
              Jan 6 '14 at 16:20











            • Thanks very much! :)

              – bryanjclark
              Jan 6 '14 at 19:18











            • I tried, but some of the error occured, Can you send this sample

              – SBM
              Sep 16 '15 at 11:13



















            • This works great! Awesome code!!

              – Kevin van Mierlo
              Jan 6 '14 at 16:20











            • Thanks very much! :)

              – bryanjclark
              Jan 6 '14 at 19:18











            • I tried, but some of the error occured, Can you send this sample

              – SBM
              Sep 16 '15 at 11:13

















            This works great! Awesome code!!

            – Kevin van Mierlo
            Jan 6 '14 at 16:20





            This works great! Awesome code!!

            – Kevin van Mierlo
            Jan 6 '14 at 16:20













            Thanks very much! :)

            – bryanjclark
            Jan 6 '14 at 19:18





            Thanks very much! :)

            – bryanjclark
            Jan 6 '14 at 19:18













            I tried, but some of the error occured, Can you send this sample

            – SBM
            Sep 16 '15 at 11:13





            I tried, but some of the error occured, Can you send this sample

            – SBM
            Sep 16 '15 at 11:13













            3














            Another way I figured out to do this is as follows.



            In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.



            if ([text isEqualToString:@"#"]) {
            recordingHashTag = YES;
            startParse = range.location;

            }else if ([text isEqualToString:@" "]) {
            currentHashTag = nil;
            recordingHashTag = NO;
            theTable.hidden = YES;

            }

            if (recordingHashTag == YES) {
            NSString *value;
            if (startParse > [textView.text length] - startParse) {
            value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
            [self filterHashTagTableWithHash:value];
            }
            }


            If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.



            -(void)filterHashTagTableWithHash:(NSString *)hash{

            [self.filterHashTagArray removeAllObjects];

            for (NSString *hashTag in self.hashTagArray ){
            NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
            if (result.location != NSNotFound) {
            [filterHashTagArray addObject:hashTag];
            }
            }
            if (filterHashTagArray.count) {
            theTable.hidden = NO;
            }else{
            theTable.hidden = YES;
            }

            [self.theTable reloadData];
            }


            The final step is to insert the hash tag when the user clicks on the entry in the table.



                - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
            UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];

            NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
            textViewComment.text = newString;
            }


            Just don't forget to clear out your variables when a user backspaces mid hash tag.






            share|improve this answer






























              3














              Another way I figured out to do this is as follows.



              In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.



              if ([text isEqualToString:@"#"]) {
              recordingHashTag = YES;
              startParse = range.location;

              }else if ([text isEqualToString:@" "]) {
              currentHashTag = nil;
              recordingHashTag = NO;
              theTable.hidden = YES;

              }

              if (recordingHashTag == YES) {
              NSString *value;
              if (startParse > [textView.text length] - startParse) {
              value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
              [self filterHashTagTableWithHash:value];
              }
              }


              If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.



              -(void)filterHashTagTableWithHash:(NSString *)hash{

              [self.filterHashTagArray removeAllObjects];

              for (NSString *hashTag in self.hashTagArray ){
              NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
              if (result.location != NSNotFound) {
              [filterHashTagArray addObject:hashTag];
              }
              }
              if (filterHashTagArray.count) {
              theTable.hidden = NO;
              }else{
              theTable.hidden = YES;
              }

              [self.theTable reloadData];
              }


              The final step is to insert the hash tag when the user clicks on the entry in the table.



                  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
              UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];

              NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
              textViewComment.text = newString;
              }


              Just don't forget to clear out your variables when a user backspaces mid hash tag.






              share|improve this answer




























                3












                3








                3







                Another way I figured out to do this is as follows.



                In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.



                if ([text isEqualToString:@"#"]) {
                recordingHashTag = YES;
                startParse = range.location;

                }else if ([text isEqualToString:@" "]) {
                currentHashTag = nil;
                recordingHashTag = NO;
                theTable.hidden = YES;

                }

                if (recordingHashTag == YES) {
                NSString *value;
                if (startParse > [textView.text length] - startParse) {
                value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
                [self filterHashTagTableWithHash:value];
                }
                }


                If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.



                -(void)filterHashTagTableWithHash:(NSString *)hash{

                [self.filterHashTagArray removeAllObjects];

                for (NSString *hashTag in self.hashTagArray ){
                NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
                if (result.location != NSNotFound) {
                [filterHashTagArray addObject:hashTag];
                }
                }
                if (filterHashTagArray.count) {
                theTable.hidden = NO;
                }else{
                theTable.hidden = YES;
                }

                [self.theTable reloadData];
                }


                The final step is to insert the hash tag when the user clicks on the entry in the table.



                    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
                UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];

                NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
                textViewComment.text = newString;
                }


                Just don't forget to clear out your variables when a user backspaces mid hash tag.






                share|improve this answer















                Another way I figured out to do this is as follows.



                In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.



                if ([text isEqualToString:@"#"]) {
                recordingHashTag = YES;
                startParse = range.location;

                }else if ([text isEqualToString:@" "]) {
                currentHashTag = nil;
                recordingHashTag = NO;
                theTable.hidden = YES;

                }

                if (recordingHashTag == YES) {
                NSString *value;
                if (startParse > [textView.text length] - startParse) {
                value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
                [self filterHashTagTableWithHash:value];
                }
                }


                If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.



                -(void)filterHashTagTableWithHash:(NSString *)hash{

                [self.filterHashTagArray removeAllObjects];

                for (NSString *hashTag in self.hashTagArray ){
                NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
                if (result.location != NSNotFound) {
                [filterHashTagArray addObject:hashTag];
                }
                }
                if (filterHashTagArray.count) {
                theTable.hidden = NO;
                }else{
                theTable.hidden = YES;
                }

                [self.theTable reloadData];
                }


                The final step is to insert the hash tag when the user clicks on the entry in the table.



                    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
                UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];

                NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
                textViewComment.text = newString;
                }


                Just don't forget to clear out your variables when a user backspaces mid hash tag.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 15 '14 at 14:58









                rihe

                1,18832047




                1,18832047










                answered Jun 7 '13 at 17:21









                BuenoBueno

                1,1551111




                1,1551111






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8281098%2fsuggest-tags-while-typing-like-twitter-for-iphone-uitextview%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                    ComboBox Display Member on multiple fields

                    Is it possible to collect Nectar points via Trainline?