You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中使用Location包装器解码CLLocation变量报错求助

解决CLLocation Codable扩展中的类型不匹配问题

问题场景

为CLLocation实现Codable扩展时,解码FriendBase结构体的lastKnownLocation属性时出现错误:Cannot assign value of type 'Location' to type 'CLLocation?',相关代码如下:

原FriendBase结构体及解码扩展

struct FriendBase: Identifiable, Encodable {
    var id: UUID = UUID()
    var firstName: String
    var lastKnownLocation: CLLocation? = nil
    
    enum CodingKeys: String, CodingKey {
        case id
        case firstName
        case lastKnownLocation
    }
}

extension FriendBase: Decodable {
    init(from decoder: Decoder) throws {
        let value = try decoder.container(keyedBy: CodingKeys.self)
        
        id = try value.decode(UUID.self, forKey: .id)
        firstName = try value.decode(String.self, forKey: .firstName)
        lastKnownLocation = try value.decode(Location.self, forKey: .lastKnownLocation)
    }
}

原CLLocation扩展及中间模型

extension CLLocation: Encodable {
    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
        case altitude
        case horizontalAccuracy
        case verticalAccuracy
        case speed
        case course
        case timestamp
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(coordinate.latitude, forKey: .latitude)
        try container.encode(coordinate.longitude, forKey: .longitude)
        try container.encode(altitude, forKey: .altitude)
        try container.encode(horizontalAccuracy, forKey: .horizontalAccuracy)
        try container.encode(verticalAccuracy, forKey: .verticalAccuracy)
        try container.encode(speed, forKey: .speed)
        try container.encode(course, forKey: .course)
        try container.encode(timestamp, forKey: .timestamp)
    }
}

struct Location: Codable {
    let latitude: CLLocationDegrees
    let longitude: CLLocationDegrees
    let altitude: CLLocationDistance
    let horizontalAccuracy: CLLocationAccuracy
    let verticalAccuracy: CLLocationAccuracy
    let speed: CLLocationSpeed
    let course: CLLocationDirection
    let timestamp: Date
}

extension CLLocation {
    convenience init(model: Location) {
      self.init(coordinate: CLLocationCoordinate2DMake(model.latitude, model.longitude), altitude: model.altitude, horizontalAccuracy: model.horizontalAccuracy, verticalAccuracy: model.verticalAccuracy, course: model.course, speed: model.speed, timestamp: model.timestamp)
     }
}

解决方案

方案1:基于现有Location模型修复类型转换

错误核心是Location实例无法直接赋值给CLLocation?类型属性,需先解码Location,再通过你定义的便利初始化器转换为CLLocation,同时用decodeIfPresent处理可选值(避免lastKnownLocation为nil时解码失败):

修改FriendBase的Decodable扩展:

extension FriendBase: Decodable {
    init(from decoder: Decoder) throws {
        let value = try decoder.container(keyedBy: CodingKeys.self)
        
        id = try value.decode(UUID.self, forKey: .id)
        firstName = try value.decode(String.self, forKey: .firstName)
        // 先解码Location(若存在),再转换为CLLocation
        if let locationModel = try value.decodeIfPresent(Location.self, forKey: .lastKnownLocation) {
            lastKnownLocation = CLLocation(model: locationModel)
        }
    }
}

方案2:直接让CLLocation遵循Decodable(更简洁)

可以省去中间的Location结构体,直接为CLLocation实现Decodable协议:

extension CLLocation: Decodable {
    enum CodingKeys: String, CodingKey {
        case latitude, longitude, altitude, horizontalAccuracy, verticalAccuracy, speed, course, timestamp
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let latitude = try container.decode(CLLocationDegrees.self, forKey: .latitude)
        let longitude = try container.decode(CLLocationDegrees.self, forKey: .longitude)
        let altitude = try container.decode(CLLocationDistance.self, forKey: .altitude)
        let horizontalAccuracy = try container.decode(CLLocationAccuracy.self, forKey: .horizontalAccuracy)
        let verticalAccuracy = try container.decode(CLLocationAccuracy.self, forKey: .verticalAccuracy)
        let speed = try container.decode(CLLocationSpeed.self, forKey: .speed)
        let course = try container.decode(CLLocationDirection.self, forKey: .course)
        let timestamp = try container.decode(Date.self, forKey: .timestamp)
        
        self.init(coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
                  altitude: altitude,
                  horizontalAccuracy: horizontalAccuracy,
                  verticalAccuracy: verticalAccuracy,
                  course: course,
                  speed: speed,
                  timestamp: timestamp)
    }
}

此时FriendBase的解码代码可简化为:

extension FriendBase: Decodable {
    init(from decoder: Decoder) throws {
        let value = try decoder.container(keyedBy: CodingKeys.self)
        
        id = try value.decode(UUID.self, forKey: .id)
        firstName = try value.decode(String.self, forKey: .firstName)
        lastKnownLocation = try value.decodeIfPresent(CLLocation.self, forKey: .lastKnownLocation)
    }
}

内容的提问来源于stack exchange,提问作者user21104171

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:54:50