iOS development has a point that often causes confusion.
It is the difference between Objective-C categories and Swift extensions.
Both seem similar because they add functionality to an existing class, so it is easy to assume they are the same concept.
The short answer is that they look alike, but their applicable types and behavior differ considerably.
A category applies only to classes and works at runtime, while an extension also applies to structs, enums, and protocols and is determined at compile time.
Today, we will compare the two from a practical perspective.
What is an Objective-C category?
A category is syntax for adding methods without subclassing an existing class.
For example, you can add your own methods to framework classes such as NSString.
You do not need the source code.
// NSString Add an email validation method
@interface NSString (Validation)
- (BOOL)isValidEmail;
@end
The key point is that the method is attached to the class at runtime.
This makes categories flexible, but if two categories define the same method, there is also a risk that which one takes precedence is not guaranteed.
When category names collide, they can easily lead to bugs whose cause is difficult to identify.
How is a Swift extension different?
It is helpful to think of Swift extensions as an expanded version of categories.
They can add not only methods, but also computed properties, initializers, nested types, and protocol conformances.
Most importantly, they are not limited to classes.
They also apply to structs, enums, and protocols.
// String Add a computed property
extension String {
var isValidEmail: Bool {
contains("@") && contains(".")
}
}
In particular, protocol extensions can provide default implementations, a powerful capability that Objective-C categories do not have.
They significantly reduce duplicated code.
Category vs extension: the key differences at a glance
For anyone who finds this confusing, I have summarized it in a table. (Based on 2026 syntax)
| Category | Objective-C category | Swift extension |
|---|---|---|
| Applicable types | Classes only | Classes, structs, enums, and protocols |
| Computed properties | Not directly supported | Supported |
| Stored properties | Not supported | Not supported |
| Default protocol implementation | Not supported | Supported |
| Method name collisions | Runtime risk | Prevented at compile time |
| When it takes effect | Runtime | Compile time |
There is one thing they have in common.
Neither can add stored properties.
If you really need to attach state, you have to use Objective-C’s associated object mechanism, but it is not exactly recommended.
When should you use each one in practice?
Here are the criteria I have developed through working on projects.
- For a pure Swift project, I use extensions without hesitation.
- When maintaining legacy Objective-C code, I continue to use categories as they are.
- When shared functionality must be distributed across multiple types, a protocol extension is usually the right answer.
There are also many cases where both are used together.
That is because functionality created with an Objective-C category can be used directly from Swift.
Conversely, remember that a Swift extension is invisible to Objective-C unless you add @objc.
If you miss this point, bridging can easily result in a compile error.
In summary, a category is a class-only runtime extension, while an extension is a compile-time extension that covers almost every type.
Once you clearly understand their characteristics, your code structure will become much cleaner.
Wishing you enjoyable development today as well!

