Objective-C
string manipulation
substring search
programming
iOS development

How do I check if a string contains another string in Objective-C?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Substring checks are one of the most common text operations in Objective-C apps, especially for validation, filtering, and parsing user input. The API choice depends on target OS versions, case sensitivity needs, and localization rules. A good implementation favors clarity first, then adds options for case and diacritic handling where needed.

Core Method: rangeOfString:

The classic approach is rangeOfString: on NSString. It returns an NSRange; when the substring is missing, location is NSNotFound.

objective-c
1NSString *source = @"Objective-C remains widely used in Apple platforms.";
2NSString *needle = @"widely used";
3
4NSRange range = [source rangeOfString:needle];
5if (range.location != NSNotFound) {
6    NSLog(@"Found at index %lu", (unsigned long)range.location);
7} else {
8    NSLog(@"Not found");
9}

This method works on old SDKs and is still a strong default when you also care about the match position.

Why this is useful

  • You get position and length in one result.
  • You can pass options for case or direction.
  • It is available in older iOS versions where containsString: is not.

Simple Boolean Check: containsString:

If you only need yes or no, containsString: reads better.

objective-c
1NSString *source = @"UIKit text fields can update in real time.";
2NSString *needle = @"real time";
3
4BOOL contains = [source containsString:needle];
5if (contains) {
6    NSLog(@"Match found");
7} else {
8    NSLog(@"No match");
9}

Use this when match location is irrelevant. The intent is obvious during review, which helps maintenance.

Real data often has case differences, accents, and user entered variation. rangeOfString:options:range:locale: gives better control.

objective-c
1NSString *source = @"Résumé review scheduled";
2NSString *needle = @"resume";
3
4NSRange fullRange = NSMakeRange(0, source.length);
5NSRange result = [source rangeOfString:needle
6                               options:(NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch)
7                                 range:fullRange
8                                locale:[NSLocale currentLocale]];
9
10if (result.location != NSNotFound) {
11    NSLog(@"Locale-aware match");
12} else {
13    NSLog(@"No locale-aware match");
14}

This is safer for internationalized apps where strict byte style matching is not enough.

Prefix, Suffix, and Token Checks

Many bugs come from using substring search when a stricter check is required. Use the most specific API for the rule:

  • Prefix rule: hasPrefix:
  • Suffix rule: hasSuffix:
  • Whole token rule: tokenize then compare normalized tokens
objective-c
1NSString *value = @"order:12345";
2if ([value hasPrefix:@"order:"]) {
3    NSLog(@"Looks like an order key");
4}

A generic substring search would also match malformed inputs that only happen to include the token.

Example Utility Method for Reuse

Centralize search behavior in a helper to keep matching policy consistent across the project.

objective-c
1#import <Foundation/Foundation.h>
2
3BOOL StringContains(NSString *source, NSString *needle, BOOL caseInsensitive) {
4    if (source == nil || needle == nil) {
5        return NO;
6    }
7    if (needle.length == 0) {
8        return YES;
9    }
10
11    NSStringCompareOptions options = caseInsensitive ? NSCaseInsensitiveSearch : 0;
12    NSRange found = [source rangeOfString:needle options:options];
13    return found.location != NSNotFound;
14}
15
16int main(void) {
17    @autoreleasepool {
18        NSLog(@"%d", StringContains(@"Payment Pending", @"pending", YES));
19        NSLog(@"%d", StringContains(@"Payment Pending", @"pending", NO));
20    }
21    return 0;
22}

This pattern avoids duplicated logic and keeps behavior predictable.

Performance Notes

For normal app strings, built in APIs are efficient and should be preferred. Performance work is only needed for extreme workloads, such as scanning large logs repeatedly. In that case:

  • Avoid repeated lowercasing of the same large source text.
  • Cache normalized forms when practical.
  • Benchmark realistic inputs before adding complexity.

Most string search slowdowns are caused by unnecessary repeated work, not by the search API itself.

Common Pitfalls

  • Using containsString: in code that must support older iOS versions without compatibility checks.
  • Forgetting case or diacritic rules and rejecting valid user input.
  • Using substring matching where prefix or exact token matching is required.
  • Repeating custom comparison logic across files and creating inconsistent behavior.
  • Optimizing early without measuring real string sizes and call frequency.

Summary

  • Use rangeOfString: when you need position data or advanced options.
  • Use containsString: for clear boolean checks in modern targets.
  • Add case and diacritic options for user facing text in multilingual apps.
  • Prefer specialized APIs like hasPrefix: when rules are stricter than substring search.
  • Centralize matching policy in helpers to keep behavior consistent.

Course illustration
Course illustration

All Rights Reserved.