Swift
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Optionals
-
Section 4: Object-Oriented and Value Types
-
Section 5: Memory Management
-
Section 6: Generics and Error Handling
-
Section 7: Concurrency
-
Section 8: Working with Collections
-
Section 9: Codable and Data Handling
-
Section 10: Protocol-Oriented Programming
-
Section 11: Testing and Tooling
-
Section 12: Practical Projects
-
Section 13: Interview Practice
-
Section 14: More Practice Exercises
-
Section 15: More Standard Library
-
Section 16: Advanced Concurrency
-
Section 17: Foundation Framework Deep Dive
-
Section 18: URLSession and Networking Deep Dive
-
Section 19: Combine Framework
-
Section 20: SwiftUI Fundamentals for Swift Developers
-
Section 21: Server-Side Swift with Vapor
-
Section 22: Swift Package Manager Deep Dive
-
Section 23: Swift Concurrency Deep Dive
-
Section 24: More Language Features
-
Section 25: Error Handling Deep Dive
-
Section 26: Testing Deep Dive
-
Section 27: Data Structures and Algorithms in Swift
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Swift Macros (Swift 5.9+)
-
Section 31: Property Wrappers Ecosystem
-
Section 32: Swift Interop Deep Dive
-
Section 33: iOS App Architecture Patterns
-
Section 34: Performance and Debugging
-
Section 35: App Distribution and CI/CD
-
Section 36: More Practical Projects
-
Section 37: SwiftData and Persistence
-
Section 38: More Design Patterns
-
Section 39: More Review and Practice
-
Section 40: More Foundation Deep Dive
-
Section 41: Advanced Collections in Swift
-
Section 42: Advanced Generics Practice
-
Section 43: UIKit for Legacy and Hybrid Apps
-
Section 44: watchOS and visionOS Development Basics
-
Section 45: More Networking Patterns
-
Section 46: More Testing Practice
-
Section 47: Accessibility in Swift Apps
-
Section 48: Localization
-
Section 49: More Practical Projects Round 2
-
Section 50: Swift Charts Framework
-
Section 51: More Interview and Algorithm Practice
-
Section 52: Final Practice and Mastery
-
Section 53: Swift Compiler and Build System
-
Section 54: More Concurrency Practice
-
Section 55: App Store Guidelines and Review
-
Section 56: More Design and Architecture
76: NSRegularExpression vs Swift Regex
A few years ago, I was reviewing a PR for a junior dev who was implementing a simple email validation check. The code worked in the happy path, but the moment a user entered a string with an emoji, the app crashed. The culprit? NSRegularExpression. He was calculating a range using NSRange and then trying to apply that range directly to a Swift String. Because Swift strings are not just arrays of characters—they're collections of extended grapheme clusters—the indices didn't align. It's a classic trap that almost every Swift developer has fallen into at least once.
The Friction of NSRegularExpression
For a long time, NSRegularExpression was our only real option. It's essentially a wrapper around the ICU library, which means it speaks the language of Objective-C. When you use it, you aren't working with Swift's native string indices; you're working with NSRange. Converting between the two requires a fair amount of boilerplate, usually involving utf16 views, which feels clunky and error-prone.
// The old, verbose way
let pattern = "[0-9]{5}"
let regex = try! NSRegularExpression(pattern: pattern)
let text = "Order number 12345"
let range = NSRange(text.startIndex..., in: text)
if let match = regex.firstMatch(in: text, options: [], range: range) {
if let swiftRange = Range(match.range, in: text) {
let result = text[swiftRange]
print("Found: \(result)")
}
}
Notice how much "ceremony" is involved here. You have to manually handle the NSRange, cast it back to a Swift Range, and deal with multiple layers of optional unwrapping. It's a lot of noise for a very simple operation.
Strongly Typed Regex Literals
Starting with Swift 5.7, we got the Regex type and, more importantly, regex literals. Now, you can wrap your pattern in forward slashes (/.../), and the compiler actually checks your regex at compile time. If you forget a closing parenthesis or misplace a quantifier, you'll get a compiler error instead of a runtime crash. This is a massive win for developer productivity.
Beyond the syntax, the biggest improvement is the integration with Swift's type system. When you use capturing groups, Swift can return the matches as a tuple of strings (or other types), removing the need to manually slice the original string using ranges.
// The modern Swift way
let text = "Order number 12345"
if let match = text.firstMatch(of: /[0-9]{5}/) {
print("Found: \(match.0)")
}
// Even better: Named Captures
let logEntry = "ERROR: Database timeout at 10:45AM"
let regex = /^(?[A-Z]+): (?.+)$/
if let match = logEntry.firstMatch(of: regex) {
print("Level: \(match.level)")
print("Message: \(match.message)")
}
I love how the named captures work here. The compiler generates a type that knows exactly which names you defined in the pattern. You get autocomplete for match.level and match.message, which makes the code significantly more readable and maintainable.
Choosing the Right Tool
You might be wondering if NSRegularExpression is completely obsolete. Not quite, but it's close. You'll still need it if you're targeting very old versions of iOS or macOS that don't support Swift 5.7+. Additionally, if you need to build a regex dynamically from user input at runtime, Regex(pattern: ) is the way to go, but the underlying engine is still the modern one.
My rule of thumb is simple: if you're on a modern toolchain, never touch NSRegularExpression unless you have a very specific legacy requirement. The safety of compile-time checking and the elimination of NSRange bugs make the new Regex type a no-brainer.
📋 Practical Task
Building a Product SKU Parser
You are working on an inventory app. Product SKUs follow a strict format: three uppercase letters, a hyphen, four digits, and a trailing single letter (e.g., "APP-1234-B" or "TSH-9021-S").
Your task is to write a function called parseSKU(_ input: String) that uses a Swift Regex literal to validate the SKU and extract the category (the first three letters) and the size (the final letter) into a tuple.
- If the SKU is valid, return a tuple:
(category: String, size: String). - If the SKU is invalid, return
nil.
Requirements:
- Use a regex literal (
/.../). - Use named captures for
categoryandsizeto keep the code clean. - Test your function with "LAP-5566-M" (should succeed) and "lap-5566-m" or "LAP-556-M" (should fail).
There are no comments for now.