1

The following class provides a mutating function to change its property:

class Person {

    struct Location {
        var coordinate: CLLocationCoordinate2D!
        var city: String?

        mutating func setLocationNameFromCoordinate(completion:(()->())?) {

            let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
            CLGeocoder().reverseGeocodeLocation(location) { (placemarks: [CLPlacemark]?, error: NSError?) in

                guard let city = placemarks?.first?.locality where error == nil else {
                    return
                }

                self.city = city //1
                completion?()
            }
        }
    }

    var location: Location?
}

The function is called like so:

person.location?.setLocationNameFromCoordinate() {
    print(person.location?.city) //2
}

However, at 1 the city name is set, looking at it from inside the location Struct, but at 2 the city name is not set for the object. What am I doing wrong here?

Manuel
  • 14,274
  • 6
  • 57
  • 130
  • @Hamish yes, and `person.location?.coordinate` has values. – Manuel Aug 25 '16 at 11:39
  • 1
    This cannot work because `reverseGeocodeLocation` works asynchronously. The completion handler which sets the city is called much later after the `print` line. – vadian Aug 25 '16 at 11:41
  • @vadian, the mutating function actually has a completion handler as well, so I am calling print only when `reverseGeocodeLocation` has completed. Updated the code. – Manuel Aug 25 '16 at 11:43
  • 1
    You can change a var from outside a struct, but you cannot change it from its own methods. Try this: setLocationNameFromCoordinate(completion: (city: String) -> Void) { completion(city: city) } – Gnanavadivelu Aug 25 '16 at 12:08
  • @Gnanavadivelu Thanks, this is was I ended up doing. Do you have an explanation or a reference to why a Struct cannot change its own property while a class can? – Manuel Aug 25 '16 at 12:11

2 Answers2

1

You can change a var from outside a struct, but you cannot change it from its own methods. You can try like this.

class Person {

    struct Location {
        var coordinate: CLLocationCoordinate2D!
        var city: String?

        mutating func setLocationNameFromCoordinate(completion: (city: String) -> Void) {

            let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
            CLGeocoder().reverseGeocodeLocation(location) { (placemarks: [CLPlacemark]?, error: NSError?) in

                guard let city = placemarks?.first?.subLocality where error == nil else {
                    return
                }

                self.city = city //Breakpoint1
                completion(city: city)

            }
        }
    }

    var location: Location?
}
Muhammad Adnan
  • 2,668
  • 15
  • 27
Gnanavadivelu
  • 263
  • 4
  • 13
  • But I see many other examples where mutable structs (`var`) are modifying their properties with a `mutating` function. So why doesn't it work in my case? Also, what is the `mutating` keyword for if not for mutating properties? http://stackoverflow.com/a/26447291/1870795 – Manuel Aug 25 '16 at 12:24
0

I write some sample codes, I think it's familiar to yours, and it's result just in right way I think.

enter image description here

I pass the location it self out with closure, and I checked the value of it is the same with a.location?.city

Edit 1:

enter image description here

Klein Mioke
  • 1,261
  • 2
  • 14
  • 23
  • This is the same as Gnanavadivelu's answer. I would like to know how the struct can mutate itself, given that there seem to be code example that just do this, see my comment at Gnanavadivelu's answer. – Manuel Aug 25 '16 at 14:10
  • 1
    @Manuel Gnanavadivelu's maybe wrong I think, `mutating` keyword means the function will mutate the properties in struct. And see my edit, it goes the same way with yours. So I think your problem maybe not relevant to `mutating`, try to find something else like `reference type`. – Klein Mioke Aug 26 '16 at 03:32
  • If you change the variable outside reverseGeocodeLocation closure, it will modify city name. http://stackoverflow.com/questions/37851249/swift-mutable-structs-in-closure-of-class-and-struct-behave-differently – Gnanavadivelu Aug 26 '16 at 06:03