Search code examples
swiftswift-extensions

Swift struct extension function - "Cannot assign to 'origin' in 'self'"


Structs in Swift can contain functions and can have extensions. Cool! Looks like a neat way to make this function available to more classes and to reduce argument passing. Here's the way the function originally looked in a map view controller:

    func expandTrackRectToCoordinate(coordinate : CLLocationCoordinate2D) {

    let point = MKMapPointForCoordinate(coordinate)
    let newRect = MKMapRectMake(point.x, point.y, 0.0, 0.0)

    if MKMapRectIsNull(trackRect) {
        trackRect = MKMapRectMake(point.x, point.y, 0.0, 0.0)
    } else {
        trackRect = MKMapRectUnion(trackRect, newRect)
    }
}

trackRect was a MKMapRect member of the class.

The MKMapRect expands to include each point so that the map can be reset to the entire region as required, showing all points.

I tried to make this an extension on MKMapRect (partial - shown up until the error):

extension MKMapRect {

func expandToIncludeCoordinate(coordinate : CLLocationCoordinate2D) {

    let point = MKMapPointForCoordinate(coordinate)
    let newRect = MKMapRectMake(point.x, point.y, 0.0, 0.0)

    if MKMapRectIsNull(self) {
        self.origin = point       <-------- Cannot assign to 'origin' in 'self'
        self.size = CGSizeZero
    } else {

I did not expect to be able to just assign to self but I did expect to be able to assign to the struct's members. How can this be done?


Solution

  • Structs in Swift generally are considered to be immutable, unless you specifically mark their methods as mutating:

    extension MKMapRect {
    
        mutating func expandToIncludeCoordinate(coordinate : CLLocationCoordinate2D) {
    
            let point = MKMapPointForCoordinate(coordinate)
            let newRect = MKMapRectMake(point.x, point.y, 0.0, 0.0)
    
            if MKMapRectIsNull(self) {
                self.origin = point
    
                // Another problem here is that CGSize is not the same as MKMapSize
                self.size = MKMapSize(width: 0, height: 0)
            } else {
                ...
                ...
            }
        }
    }
    

    Reference