replacingOccurrences(of:with:) from Foundation for any deployment target, or replacing(_:with:) on iOS 16+ / Swift 5.7. Both return a new String — Swift strings are value types, so you must assign the result back. For a single match, pass maxReplacements: 1 or use replacingCharacters(in:with:) with a range.Why this happens
Swift’s String has no replace(_:with:) method. If you write myString.replace(" ", with: "+") the compiler stops with value of type 'String' has no member 'replace'. Most people hit this after copying a snippet from an old tutorial, because the method was renamed in Swift 3 and the pre-Swift 3 name no longer exists either.
The second half of the confusion is value semantics. String is a struct, so no replacement method mutates the receiver in place. Every API below returns a brand-new string, and the original is untouched until you assign the result back to a variable.
Finally, there are now two families of APIs: the long-standing Foundation method replacingOccurrences(of:with:options:range:), and the newer standard-library replacing(_:with:maxReplacements:) added in Swift 5.7 (iOS 16, macOS 13). Both are correct; the choice depends on your deployment target and whether you want the extra options.
How to fix it
1. Use replacingOccurrences(of:with:) for any deployment target
This is the Foundation method that has been the standard answer since Swift 3. Import Foundation and call it on the string:
import Foundation
let text = "This is my string"
let slug = text.replacingOccurrences(of: " ", with: "+")
// "This+is+my+string"
The options and range parameters are optional. When you need them, they give you case-insensitive matching, regular expressions, or a limited search window:
let shout = "Hello World".replacingOccurrences(
of: "world",
with: "Swift",
options: .caseInsensitive
)
// "Hello Swift"
let digitsGone = "a1b2c3".replacingOccurrences(
of: "[0-9]",
with: "",
options: .regularExpression
)
// "abc"
If you only want to touch part of the string, pass a range instead of nil:
let full = "one two one"
let head = full.startIndex..<full.index(full.startIndex, offsetBy: 7)
let partial = full.replacingOccurrences(of: "one", with: "1", range: head)
// "1 two one"
2. Use replacing(_:with:maxReplacements:) on iOS 16 and later
Swift 5.7 added a native replacement method to RangeReplaceableCollection, which String conforms to. It needs no Foundation import and reads more cleanly:
let text = "This is my string with spaces"
let slug = text.replacing(" ", with: "+")
// "This+is+my+string+with+spaces"
The maxReplacements argument caps how many matches are swapped. It defaults to Int.max, so omitting it replaces everything:
let limited = text.replacing(" ", with: "+", maxReplacements: 2)
// "This+is+my string with spaces"
There is also a closure overload, useful when the replacement depends on what was matched:
let masked = "a1b2".replacing(/[0-9]/) { _ in "#" }
// "a#b#"
Remember the availability floor: this API is iOS 16.0+, macOS 13.0+, tvOS 16.0+, watchOS 9.0+. If your deployment target is lower, stay with replacingOccurrences.
3. Replace exactly one occurrence
Neither method above stops at the first match unless you tell it to. On iOS 16+ pass maxReplacements: 1. On older targets, find the range and splice it:
import Foundation
var text = "one two one"
if let range = text.range(of: "one") {
text = text.replacingCharacters(in: range, with: "1")
}
// "1 two one"
replacingCharacters(in:with:) is the right tool whenever you already have a Range<String.Index> — for example from a search field highlight — because it avoids re-scanning the whole string.
4. Swap many characters in one pass
Chaining replacingOccurrences calls re-scans the string each time. For a handful of characters, a single map over the string is faster and easier to read:
let table: [Character: Character] = [" ": "+", "-": "_", ".": "-"]
let input = "my file-name.txt"
let output = String(input.map { table[$0] ?? $0 })
// "my+file_name-txt"
For the specific case of turning a phrase into a URL slug, components(separatedBy:) plus joined(separator:) is a common alternative, though it only handles one separator at a time:
let slug = "This is my string"
.components(separatedBy: " ")
.joined(separator: "+")
If you genuinely need reference semantics — a shared buffer mutated by several objects — wrap the text in NSMutableString and call replaceOccurrences(of:with:options:range:) on it. In SwiftUI and most app code you should not need this.
How to prevent it
- Don’t paste Swift 2 snippets:
stringByReplacingOccurrencesOfString(_:withString:options:range:)was renamed toreplacingOccurrences(of:with:options:range:)in Swift 3 and the old name is gone. - Always assign the result.
text.replacingOccurrences(...)on its own line compiles and does nothing, becauseStringis a value type. - Check your deployment target before reaching for
replacing(_:with:); it is iOS 16+ only. - Prefer
.literalmatching when the search string contains regex metacharacters like.,*or[, otherwise.regularExpressionwill surprise you. - Be careful with combining characters and emoji.
replacingOccurrencesworks on UTF-16 units, so replacing a base letter inside a decomposed sequence can split a grapheme cluster. - Write a unit test with an empty string and with a string that contains no matches — both should return the input unchanged.
FAQ
Why does myString.replace(" ", with: "+") not compile?
Because String has no method named replace. The compiler reports value of type 'String' has no member 'replace'. Use replacingOccurrences(of:with:) or, on iOS 16+, replacing(_:with:).
Is replacingOccurrences(of:with:) case-sensitive?
Yes, by default it performs a literal, case-sensitive comparison. Pass options: .caseInsensitive to match regardless of case, or combine options such as [.caseInsensitive, .diacriticInsensitive].
Can I replace text with a regular expression in Swift?
Yes. Pass options: .regularExpression to replacingOccurrences(of:with:) and write the pattern as the of argument, for example "\\s+" to collapse runs of whitespace into a single character.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
