自定义类符合MKAnnotation和Codable。

问题描述 投票:0回答:1

我正在用Swift for iOS开发一个小组项目应用程序,允许用户使用Firebase保存位置作为旅游的一部分。我们的 User 对象是一个自定义类,我们希望能符合 Codable 用于CodableFirebase CocoaPod。然而,当试图使CocoaPod符合以下条件时,问题就出现了 Location 反对 Codable 因为它也要符合 MKAnnotation...而我们都是相当新的。有可能有些解决方案在我的脑海中消失了... 完全有可能。

这就是我们的 Location 对象。

import Foundation
import MapKit
import CoreLocation
import CodableFirebase

class Location: NSObject, MKAnnotation {

    var coordinate: CLLocationCoordinate2D
    var locationName: String?
    var locationDescription: String?
    var locationImage: UIImage?

    init(coordinate: CLLocationCoordinate2D, locationName: String, locationDescription: String, locationImage: UIImage) {

        self.coordinate = coordinate
        self.locationName = locationName
        self.locationDescription = locationDescription
        self.locationImage = locationImage

    }
}

这就是我们的 User 模型对象。

import UIKit
import CloudKit

class User {

    //MARK: - Editable Public Profile Info
    var firstName: String
    var lastName: String
    var userStateOfOrigin: States
    var userImage: UIImage?
    var aboutMe: String
    var languages: [Language]

    //MARK: - Editable Personal Info (Includes all Public Profile info)
    var email: String?
    var phoneNumber: String?

    //MARK: - Hidden Variables
    var userId: String
    var userCreatedTours: [Tour]
    var savedLocations: [Location]
    var savedTours: [Tour]
    var bookedTours: [Tour]
    var previouslyExperiencedTours: [Tour]
    var userRating: [Rating]

    init(firstName: String, lastName: String, userStateOfOrigin: States, userImage: UIImage? = nil, aboutMe: String, languages: [Language] = [], email: String?, phoneNumber: String? = "", userId: String, userCreatedTours: [Tour] = [], savedLocations: [Location] = [], savedTours: [Tour] = [], bookedTours: [Tour] = [], previouslyExperiencedTours: [Tour] = [], userRating: [Rating] = []) {

        // editable Public info
        self.firstName =  firstName
        self.lastName = lastName
        self.userStateOfOrigin = userStateOfOrigin
        self.userImage = userImage
        self.aboutMe = aboutMe
        self.languages = languages

        // editable personal info
        self.email = email
        self.phoneNumber = phoneNumber

        // Hidden Variables
        self.userId = userId
        self.userCreatedTours = userCreatedTours
        self.savedLocations = savedLocations
        self.savedTours = savedTours
        self.bookedTours = bookedTours
        self.previouslyExperiencedTours = previouslyExperiencedTours
        self.userRating = userRating

    }
}

我们确实有一些其他的自定义对象,但我想一旦这个问题解决了,我们应该可以很容易地使这些对象符合。Codable. 最终,如果能让这两者都符合以下条件就更好了 Codable 以便于与Firebase一起使用。然而,如果这是不可能的,或者是最谨慎的路线,我非常愿意接受建议。我真的很感激。

ios swift mkannotation codable cllocationcoordinate2d
1个回答
0
投票

一些观察。

  1. MKAnnotation 协议有 titlesubtitle 属性(许多注解视图都使用)。我建议将 locationNamelocationDescription,分别是。

  2. 我建议将这些属性 dynamic这样,如果您更新了它们,变化就会在它们各自的注解视图上更新。

    比如说 的文件 coordinate 说。

    您对该属性的实现必须符合键值观测(KVO)。有关如何实现对 KVO 支持的更多信息,请参阅 键值观测编程指南.

    在Swift中,简单的方法是使用 dynamic 关键字。

  3. 要做到这一点 Codable,要么。

    • 财产必须是 Codable也是;或

    • 你将需要手动实现 init(from:)encode(to:) 来分别进行解码和编码。参见 编码和解码自定义类型 的例子。 

    鉴于无论是 CLLocationCoordinate2D 也不 UIImage 符合 Codable我倾向于第二种选择。

  4. 一个非常小的问题,但我可能不会使用类型名为 Location,而是使用一些带有 Annotation 的名称中,以明确对象是什么。它还有助于避免与位置对象混淆,例如:. CLLocation. 我使用了 CustomAnnotation 以下,这不是一个很好的名字,但希望你能想出一个在你的应用程序中更有意义的名字,同时也有 Annotation 内的名称。

因此,把这一切拉到一起,你可能会做这样的事情。

class CustomAnnotation: NSObject, MKAnnotation, Codable {
    dynamic var coordinate: CLLocationCoordinate2D
    dynamic var title: String?
    dynamic var subtitle: String?
    dynamic var image: UIImage?

    init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?, locationImage: UIImage?) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
        self.image = locationImage
    }

    enum CodingKeys: String, CodingKey {
        case title, subtitle, image, latitude, longitude
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        title = try values.decodeIfPresent(String.self, forKey: .title)
        subtitle = try values.decodeIfPresent(String.self, forKey: .subtitle)

        let latitude = try values.decode(CLLocationDegrees.self, forKey: .latitude)
        let longitude = try values.decode(CLLocationDegrees.self, forKey: .longitude)
        coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

        let data = try values.decodeIfPresent(Data.self, forKey: .image)
        image = data.flatMap { UIImage(data: $0) }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        try container.encodeIfPresent(title, forKey: .title)
        try container.encodeIfPresent(subtitle, forKey: .subtitle)
        try container.encode(coordinate.latitude, forKey: .latitude)
        try container.encode(coordinate.longitude, forKey: .longitude)
        try container.encodeIfPresent(image?.pngData(), forKey: .image)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.