Skip to main content

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

swift
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:

swift
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:

swift
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:

swift
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:

swift
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:

swift
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:

swift
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:

  1. Extension Properties:

    • Add functionality to existing types
    • Can't add stored properties
    • Available to all instances of that type
  2. Property Wrappers:

    • Define reusable property behavior
    • Can have stored properties
    • Applied selectively to individual properties

Best Practices for Extension Properties

  1. Keep It Cohesive: Add properties that logically belong to the type you're extending.
  2. Document Your Extensions: Clearly comment what your extension properties do.
  3. Avoid Side Effects: Computed properties should generally avoid causing side effects.
  4. Consider Performance: For frequently accessed properties, be mindful of computation costs.

Common Mistakes and Limitations

  1. Attempting to Add Stored Properties:
swift
extension String {
// This will NOT compile!
var extraData: String = ""
}

This won't work because extensions can't add stored properties.

  1. 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

  1. Create an extension on Int that adds a property to check if a number is prime.
  2. Add a property to UIColor that returns a lighter version of the color.
  3. Extend the Array type with a property that returns the average of its elements (assume the array contains numbers).
  4. Create an extension on String that adds a property returning the string with its characters reversed.
  5. Add a computed property to Date that returns the date formatted as "YYYY-MM-DD".

Additional Resources

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! :)