Swift Extension Properties
Extensions in Swift allow you to add new functionality to existing types, and one of the most powerful features is the ability to add new properties to types you don't have access to modify. In this guide, we'll explore how to use extension properties to enhance Swift types.
Introduction to Extension Properties
When working with Swift, you might encounter situations where you want to add new properties to existing types like String
, Int
, or even your custom classes. Extensions allow you to do this without subclassing or modifying the original source code.
However, there's an important limitation to understand: you can only add computed properties in extensions, not stored properties. This is because stored properties would require additional memory allocation for existing instances of the type.
Computed Properties in Extensions
Computed properties don't actually store values. Instead, they provide a getter and an optional setter to retrieve and set other properties indirectly.
Basic Syntax
extension SomeType {
var newComputedProperty: Type {
get {
// Return some value
}
set {
// Set some value (optional)
}
}
}
Read-Only Computed Property Example
Let's add a property to String
that returns whether the string contains only digits:
extension String {
var isNumeric: Bool {
return self.allSatisfy { $0.isNumber }
}
}
// Usage
let phoneNumber = "12345"
let name = "John"
print(phoneNumber.isNumeric) // Output: true
print(name.isNumeric) // Output: false
This extension adds an isNumeric
property to all strings, making it easy to check if a string contains only numeric characters.
Read-Write Computed Property Example
Let's create a more complex example by adding a temperature conversion property to Double
:
extension Double {
var celsiusToFahrenheit: Double {
get {
return (self * 9/5) + 32
}
set {
self = (newValue - 32) * 5/9
}
}
}
// Usage
var temperature = 25.0 // 25°C
print("\(temperature)°C is \(temperature.celsiusToFahrenheit)°F")
// Output: 25.0°C is 77.0°F
temperature.celsiusToFahrenheit = 68.0 // Setting to 68°F
print("New temperature: \(temperature)°C")
// Output: New temperature: 20.0°C
In this example, the computed property provides a convenient way to convert between Celsius and Fahrenheit temperatures.
Type Properties in Extensions
You can also add static/type properties to types using extensions:
extension Double {
static var absoluteZeroInCelsius: Double {
return -273.15
}
}
// Usage
print("Absolute zero is \(Double.absoluteZeroInCelsius)°C")
// Output: Absolute zero is -273.15°C
Practical Applications
Adding Convenience Properties to UIKit
For iOS developers, extensions are incredibly useful for adding convenience properties to UIKit classes:
extension UIView {
var width: CGFloat {
get { return self.frame.size.width }
set { self.frame.size.width = newValue }
}
var height: CGFloat {
get { return self.frame.size.height }
set { self.frame.size.height = newValue }
}
}
// Usage
let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
print("View width: \(myView.width)")
// Output: View width: 100.0
myView.width = 200
print("New view width: \(myView.width)")
// Output: New view width: 200.0
Enhancing Foundation Types
Extension properties can make standard library types more powerful:
extension Date {
var dayOfWeek: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
return dateFormatter.string(from: self)
}
}
// Usage
let today = Date()
print("Today is \(today.dayOfWeek)")
// Output: Today is Wednesday (or whatever the current day is)
Adding Validation Properties
You can add validation properties to types like String
:
extension String {
var isValidEmail: Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailPred.evaluate(with: self)
}
var isValidURL: Bool {
guard let url = URL(string: self) else { return false }
return UIApplication.shared.canOpenURL(url)
}
}
// Usage
let email = "[email protected]"
print("Is valid email: \(email.isValidEmail)")
// Output: Is valid email: true
let website = "https://www.example.com"
print("Is valid URL: \(website.isValidURL)")
// Output: Is valid URL: true
Property Wrappers vs. Extension Properties
While extension properties are powerful, in newer versions of Swift, you might also consider using property wrappers for certain use cases. Here's a comparison:
-
Extension Properties:
- Add functionality to existing types
- Can't add stored properties
- Available to all instances of that type
-
Property Wrappers:
- Define reusable property behavior
- Can have stored properties
- Applied selectively to individual properties
Best Practices for Extension Properties
- Keep It Cohesive: Add properties that logically belong to the type you're extending.
- Document Your Extensions: Clearly comment what your extension properties do.
- Avoid Side Effects: Computed properties should generally avoid causing side effects.
- Consider Performance: For frequently accessed properties, be mindful of computation costs.
Common Mistakes and Limitations
- Attempting to Add Stored Properties:
extension String {
// This will NOT compile!
var extraData: String = ""
}
This won't work because extensions can't add stored properties.
- Forgetting that Properties Might Be Computed: Since extension properties are always computed, accessing them multiple times might recalculate the value each time, which could impact performance.
Summary
Extension properties in Swift provide a powerful way to add computed functionality to existing types without modifying their original implementation. While limited to computed properties, they can significantly enhance your code's readability and maintainability.
Key points to remember:
- Extensions can only add computed properties, not stored properties
- You can add both instance and type properties via extensions
- Extension properties can have getters and setters
- They're useful for adding validation, convenience, and derived values
Exercises
- Create an extension on
Int
that adds a property to check if a number is prime. - Add a property to
UIColor
that returns a lighter version of the color. - Extend the
Array
type with a property that returns the average of its elements (assume the array contains numbers). - Create an extension on
String
that adds a property returning the string with its characters reversed. - Add a computed property to
Date
that returns the date formatted as "YYYY-MM-DD".
Additional Resources
- Swift Documentation on Extensions
- Apple Developer: Using Swift Extensions
- Swift Property Wrappers Guide
Remember that extension properties are a powerful tool that can help make your code more readable and expressive when used appropriately!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)