tezvyn:

Lightweight Generics: Type Safety for Objective-C

AI-drafted, machine-checkedSource: developer.apple.comintermediate
Lightweight Generics: Type Safety for Objective-C

Lightweight generics bolt type safety onto Objective-C collections like NSArray. This lets Swift see an NSArray<NSString *> as a type-safe [String] instead of [Any], preventing runtime crashes.

WHY IT EXISTS: Before Swift, Objective-C collections like NSArray were untyped; they held objects of type id. When Swift was introduced, these collections were bridged as [Any], forcing developers to constantly cast and check types, which was unsafe and verbose. Lightweight generics were added to Objective-C to solve this interoperability problem.

THE MENTAL MODEL: Think of lightweight generics as a contract or a hint for the compiler, especially the Swift compiler. You're telling the system, "I promise this array will only contain strings." The compiler then uses this promise to provide type safety and better autocompletion, but it doesn't build a runtime wall to enforce it within Objective-C itself. It's a compile-time annotation for better code, not a runtime feature.

HOW IT WORKS: You add a type parameter in angle brackets to Objective-C collection classes. For example, a plain NSArray * becomes NSArray<NSString *> *. When the Swift compiler imports this header, it sees the generic type and bridges the NSArray as a Swift native Array<String> (or [String]). This works for NSArray, NSDictionary, and NSSet, as well as your own custom Objective-C classes. You can also define bounds on your generic types, like T: NSNumber, to require that the type is a subclass of NSNumber.

WHEN TO USE IT: Use lightweight generics in any modern Objective-C code that might be called from Swift. It's standard practice for any new Objective-C APIs. It dramatically improves the developer experience for Swift consumers of your code, making the API safer, more predictable, and self-documenting. It's essential for maintaining a clean codebase that mixes both languages.

WHEN NOT TO USE IT: Avoid them if you genuinely need a heterogeneous collection where the types are unknown until runtime. In such cases, forcing a generic type would be misleading. For pure Objective-C projects that will never interact with Swift, they provide less value, but are still good practice for clarity.

ONE CANONICAL EXAMPLE: An Objective-C method signature without generics might be (NSArray *)fetchUserIDs;. Swift would see this as func fetchUserIDs() -> [Any]. The Swift developer would have to cast every element. With lightweight generics, the signature becomes (NSArray<NSString *> *)fetchUserIDs;. Swift now sees this as func fetchUserIDs() -> [String]. The API is now type-safe, and no casting is needed on the Swift side.

Read the original → developer.apple.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.