Tengo algunas estructuras que representan ubicaciones en la Tierra que representan una ubicación simple de latitud/ longitud ( Point2D ), ubicación de latitud/longitud/altura ( Point3D ) y una ubicación con nombre, como una ubicación de nombre de aeropuerto/latitud/longitud/altura ( Airport ).
struct Point2D { var lat: Double var lon: Double } struct Point3D { var point2D: Point2D var height_m: Double } struct Airport { var name: String var point3D: Point3D } Estas estructuras se utilizan de forma jerárquica, lo que funciona bien, pero provoca un acceso .dot largo al obtener datos de una instancia de aeropuerto. Por ejemplo, para obtener el valor de latitud del aeropuerto es airport.point3D.point2D.lat que no es ideal.
let airportLHR1 = Airport(name: "LHR", point3D: Point3D(point2D: Point2D(lat: 51.5, lon: -0.5), height_m: 25.0)) print("Airport: \(airportLHR1.name). Lat,Lon: \(airportLHR1.point3D.point2D.lat), \(airportLHR1.point3D.point2D.lon)") // --> Airport: LHR. Lat,Lon: 51.5, -0.5He refactorizado la estructura del aeropuerto para 'aplanar' la propiedad .dot access, pero siento que puede haber una mejor manera de lograr esto.
struct Airport2 { var name: String private var _point3D: Point3D var lat: Double { get { _point3D.point2D.lat } set { _point3D.point2D.lat = newValue } } var lon: Double { get { _point3D.point2D.lon } set { _point3D.point2D.lon = newValue } } var height_m: Double { get { _point3D.height_m } set { _point3D.height_m = newValue } } init(name: String, lat: Double, lon: Double, height_m: Double) { self.name = name self._point3D = Point3D(point2D: Point2D(lat: lat, lon: lon), height_m: height_m) } }Acceder a los datos del aeropuerto ahora es mucho más sencillo...
let airportLHR2 = Airport2(name: "LHR", lat: 51.5, lon: -0.5, height_m: 25.0) print("Airport: \(airportLHR2.name). Lat,Lon: \(airportLHR2.lat), \(airportLHR2.lon)") // --> Airport: LHR. Lat,Lon: 51.5, -0.5... pero hay una mejor manera de hacer esto?
Suponiendo que te refieres a altitud por height , simplemente puedes usar CLLocation y, opcionalmente, extenderlo con un inicializador conveniente para hacer la vida un poco más fácil.
extension CLLocation { convenience init(lat: CLLocationDegrees, lon: CLLocationDegrees, alt: CLLocationDistance) { self.init(coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon), altitude: alt, horizontalAccuracy: 0, verticalAccuracy: 0, timestamp: .now) } } struct Airport { let name: String let loc: CLLocation } let lax = Airport(name: "LAX", loc: CLLocation(lat: 33.9416, lon: -118.4085, alt: 39.0144)) print(lax.loc.coordinate.longitude) // -118.4085 print(lax.loc.altitude) // 39.0144Yo sugeriría:
struct Coordinate { let latitude: Double let longitude: Double } struct Location { let coordinate: Coordinate let altitude: Double } struct Airport { let name: String let location: Location } extension Airport { var latitude: Double { location.coordinate.latitude } var longitude: Double { location.coordinate.longitude } }Arriba, siguiendo las mejores prácticas, he favorecido la inmutabilidad. Pero si realmente necesitas mutabilidad:
struct Coordinate { var latitude: Double var longitude: Double } struct Location { var coordinate: Coordinate var altitude: Double } struct Airport { var name: String var location: Location } extension Airport { var latitude: Double { get { location.coordinate.latitude } set { location.coordinate.latitude = newValue } } var longitude: Double { get { location.coordinate.longitude } set { location.coordinate.longitude = newValue } } } Sin relación, pero probablemente movería estas propiedades calculadas a un protocolo de Place :
protocol Place { var name: String { get } var location: Location { get } } extension Place { var latitude: Double { location.coordinate.latitude } var longitude: Double { location.coordinate.longitude } } struct Airport: Place { let name: String let location: Location }De esa manera, también puede definir lugares que no son aeropuertos y no tener que repetir estas propiedades calculadas.