- Published on
Swift’s Hidden Gem, Understanding the @retroactive Keyword
- Authors

- Name
- Omar Elsayed
Introduction
As iOS developers, we often find ourselves working with system frameworks and third-party libraries, Sometimes, we need these types to conform to certain protocols, especially when working with SwiftUI. This is where Swift’s powerful but lesser-known @retroactive keyword comes into play.
In this article, we'll dive deep into what this keyword does, why it's useful, and how to use it effectively in your iOS applications.
extension UIImage: @retroactive Identifiable {
public var id: Int { hashValue }
}
- The Challenge: Extending Types We Don’t Own
- A Real-World Example
- Understanding @retroactive
- How It Works Under the Hood
- Best Practices and Guidelines
- Advanced Usage Tips
- Common Pitfalls and Solutions
- Conclusion
The Challenge: Extending Types We Don’t Own
Imagine you’re building a SwiftUI app and need to present a UIImage in a sheet, the sheet modifier in SwiftUI requires its content to conform to the Identifiable protocol. But here's the catch: UIImage is a system type that we don't own, and it doesn't conform to Identifiable out of the box.
Traditionally, this would pose a challenge, we can’t modify the original UIImage class, and simply adding an extension might not be enough. This is exactly the kind of situation where @retroactive shines.
A Real-World Example
Let’s look at a practical example where we need to present a UIImage in a sheet:
import SwiftUI
struct ExampleForRetroactive: View {
@State private var imageToShare: UIImage?
var body: some View {
ZStack {
Color.red
}
.sheet(item: $imageToShare) { image in
Image(uiImage: image)
}
}
@ViewBuilder
func shareBottomView() -> some View {
Button {
imageToShare = UIImage(systemName: "plus")
} label: {
Text("Present Sheet")
.padding(24)
.background {
RoundedRectangle(cornerRadius: 9999)
.foregroundStyle(.ultraThinMaterial)
.frame(height: 52)
.shadow(radius: 4)
.compositingGroup()
}
}
}
}
Without making UIImage conform to Identifiable, this code wouldn't compile, Here's where @retroactive comes to the rescue:
extension UIImage: @retroactive Identifiable {
public var id: Int { hashValue }
}
Understanding @retroactive
The @retroactive keyword is a powerful attribute that allows us to:
- Add Protocol Conformance: We can make existing types conform to protocols without modifying their source code.
- Maintain Type Safety: The compiler ensures our conformance is properly implemented.
- Bridge Framework Gaps: We can make types from different frameworks work together seamlessly.
How It Works Under the Hood
When we mark an extension as @retroactive, we're telling the Swift compiler that this conformance should be applied to the type retroactively. This means:
- The conformance is checked at compile-time
- It doesn’t affect the original type’s implementation
- It’s available throughout our application’s scope
Best Practices and Guidelines
When to Use @retroactive
- System Types: When you need to add protocol conformance to UIKit, Foundation, or other system framework types.
- Third-Party Libraries: When working with types from external dependencies that need additional protocol conformance.
- Framework Bridging: When you need to make types from different frameworks work together.
When to Avoid @retroactive
- Owned Types: If you own the type, add the conformance directly instead.
- Complex Conformance: When the conformance requires significant implementation details.
- Future Conflicts: When there’s a risk of conflicting with future framework updates.
Advanced Usage Tips
Hashable Considerations
When using hashValue for identification (as in our example), be aware that:
- Hash values may change between app launches
- They should not be persisted
- They might not be unique in rare cases
extension UIImage: @retroactive Identifiable {
public var id: Int {
// Consider combining multiple properties for more unique identification
"\(size):\(scale)".hashValue
}
}
Documentation
Always document your retroactive conformances:
/// Adds Identifiable conformance to UIImage for use with SwiftUI sheet presentations
/// Note: The id is based on the image's hashValue and may change between app launches
extension UIImage: @retroactive Identifiable {
public var id: Int { hashValue }
}
Common Pitfalls and Solutions
Access Level Mismatches
- Ensure your conformance has the appropriate access level
- Remember that protocol requirements might need to be marked as public
Conformance Conflicts
- Check for existing conformances in the frameworks you’re using
- Be prepared to handle future framework updates that might add the same conformance
Performance Considerations
- Keep conformances lightweight
- Avoid expensive computations in property getters
Conclusion
The @retroactive keyword is a powerful tool in Swift that helps us bridge gaps between frameworks and add functionality to types we don't own. When used appropriately, it can make our code more elegant and maintainable.
Remember:
- Use it sparingly and only when necessary
- Document your usage clearly
- Consider the implications for future maintenance
- Keep conformances simple and focused
If you found this article helpful, don’t forget to subscribe for more Swift and iOS development content.
NOTE
Code examples in this article were tested with Swift 5.9 and iOS 17.0