Objective-C
String Search
String Array
Programming
iOS Development

String search in string array in objective c

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Objective-C provides several ways to search for a string within an NSArray of strings. containsObject: checks for exact matches, indexOfObject: returns the position, filteredArrayUsingPredicate: supports partial and case-insensitive matching with NSPredicate, and block-based enumeration gives full control over the search logic. The right method depends on whether you need exact matches, substring matches, or case-insensitive comparisons.

Exact Match with containsObject:

objc
1NSArray *names = @[@"Alice", @"Bob", @"Charlie", @"Diana"];
2
3if ([names containsObject:@"Bob"]) {
4    NSLog(@"Found Bob");
5}
6// Output: Found Bob
7
8// Case-sensitive — "bob" would NOT be found
9if ([names containsObject:@"bob"]) {
10    NSLog(@"Found bob");
11} else {
12    NSLog(@"Not found");
13}
14// Output: Not found

containsObject: uses isEqual: for comparison, which is case-sensitive for NSString.

Finding the Index with indexOfObject:

objc
1NSArray *colors = @[@"Red", @"Green", @"Blue", @"Green"];
2
3NSUInteger index = [colors indexOfObject:@"Green"];
4if (index != NSNotFound) {
5    NSLog(@"Found at index %lu", (unsigned long)index);
6}
7// Output: Found at index 1 (first occurrence)

indexOfObject: returns NSNotFound if the string is not in the array.

Substring and Case-Insensitive Search with NSPredicate

objc
1NSArray *cities = @[@"New York", @"Los Angeles", @"San Francisco", @"New Orleans"];
2
3// Case-insensitive exact match
4NSPredicate *exactMatch = [NSPredicate predicateWithFormat:@"SELF ==[c] %@", @"new york"];
5NSArray *results = [cities filteredArrayUsingPredicate:exactMatch];
6NSLog(@"%@", results);
7// Output: (New York)
8
9// Contains substring (case-insensitive)
10NSPredicate *contains = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", @"new"];
11results = [cities filteredArrayUsingPredicate:contains];
12NSLog(@"%@", results);
13// Output: (New York, New Orleans)
14
15// Begins with
16NSPredicate *beginsWith = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH[c] %@", @"san"];
17results = [cities filteredArrayUsingPredicate:beginsWith];
18NSLog(@"%@", results);
19// Output: (San Francisco)
20
21// Ends with
22NSPredicate *endsWith = [NSPredicate predicateWithFormat:@"SELF ENDSWITH[c] %@", @"angeles"];
23results = [cities filteredArrayUsingPredicate:endsWith];
24NSLog(@"%@", results);
25// Output: (Los Angeles)

Predicate modifiers: [c] = case-insensitive, [d] = diacritic-insensitive, [cd] = both.

Block-Based Enumeration

objc
1NSArray *fruits = @[@"Apple", @"Banana", @"Apricot", @"Cherry", @"Avocado"];
2
3// Find first match
4NSUInteger index = [fruits indexOfObjectPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
5    return [obj hasPrefix:@"Ap"];
6}];
7
8if (index != NSNotFound) {
9    NSLog(@"First 'Ap' fruit: %@", fruits[index]);
10}
11// Output: First 'Ap' fruit: Apple
12
13// Find all matches
14NSIndexSet *indexes = [fruits indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
15    return [obj hasPrefix:@"A"];
16}];
17
18NSArray *aFruits = [fruits objectsAtIndexes:indexes];
19NSLog(@"Fruits starting with A: %@", aFruits);
20// Output: (Apple, Apricot, Avocado)

Case-Insensitive Search with rangeOfString:

For manual case-insensitive comparison:

objc
1NSArray *items = @[@"iPhone", @"iPad", @"MacBook", @"iMac"];
2NSString *search = @"ipad";
3
4for (NSString *item in items) {
5    NSRange range = [item rangeOfString:search options:NSCaseInsensitiveSearch];
6    if (range.location != NSNotFound) {
7        NSLog(@"Found: %@", item);
8    }
9}
10// Output: Found: iPad

Regex Search with NSPredicate

objc
1NSArray *emails = @[@"[email protected]", @"[email protected]", @"[email protected]"];
2
3// Match emails ending in @example.com
4NSPredicate *regex = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @".*@example\\.com"];
5NSArray *results = [emails filteredArrayUsingPredicate:regex];
6NSLog(@"%@", results);
7// Output: ([email protected], [email protected])

MATCHES uses ICU regex syntax.

Searching in NSMutableArray

All methods above work identically with NSMutableArray. Additionally, you can remove non-matching elements:

objc
1NSMutableArray *names = [@[@"Alice", @"Bob", @"Charlie", @"Diana"] mutableCopy];
2
3// Remove names not starting with "C"
4NSPredicate *keepC = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH %@", @"C"];
5[names filterUsingPredicate:keepC];
6NSLog(@"%@", names);
7// Output: (Charlie)

Performance Considerations

MethodTime ComplexityBest For
containsObject:O(n)Quick exact match check
indexOfObject:O(n)Finding position of exact match
filteredArrayUsingPredicate:O(n)Flexible pattern matching
indexOfObjectPassingTest:O(n) worst caseCustom logic with early exit
NSSet containsObject:O(1) averageRepeated lookups in large collections

For repeated searches on a large array, convert to NSSet first:

objc
1NSSet *nameSet = [NSSet setWithArray:names];
2if ([nameSet containsObject:@"Bob"]) {
3    // O(1) lookup
4}

Common Pitfalls

  • Case sensitivity with containsObject:: containsObject: uses isEqual:, which is case-sensitive for strings. [@[@"Hello"] containsObject:@"hello"] returns NO. Use NSPredicate with [c] for case-insensitive matching.
  • Forgetting NSNotFound check: indexOfObject: returns NSNotFound (which is NSIntegerMax) when the string is not found. Using the result as an index without checking causes an out-of-bounds crash.
  • Predicate format string injection: Building predicates with stringWithFormat: instead of predicateWithFormat: can cause crashes with special characters. Always use predicateWithFormat: with %@ substitution.
  • Searching in nil arrays: Sending messages to nil in Objective-C returns nil/0/NO. [nil containsObject:@"test"] returns NO without crashing, which may hide bugs where the array was unexpectedly nil.
  • Performance with large arrays: filteredArrayUsingPredicate: scans the entire array every time. For repeated lookups, build an NSSet or NSDictionary for O(1) access.

Summary

  • Use containsObject: for simple, exact-match existence checks
  • Use indexOfObject: when you need the position of the match
  • Use NSPredicate with CONTAINS[cd], BEGINSWITH[c], or MATCHES for flexible string matching
  • Use block-based indexOfObjectPassingTest: for custom search logic with early exit
  • Convert to NSSet for O(1) lookups when searching the same collection repeatedly
  • Always check for NSNotFound before using an index returned by indexOfObject:

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.