【问题标题】:NSCoding for a non-compliant object (MKMapItem)不合规对象的 NSCoding (MKMapItem)
【发布时间】:2016-11-05 18:57:03
【问题描述】:

尝试将 MKMapItem 保存为我的自定义类的一部分。

 import UIKit
 import MapKit

 class Place: NSObject, NSCoding {

 var mapItem : MKMapItem!
 var type : Category!

 init(mapItem: MKMapItem, type: Category) {
   self.mapItem = mapItem
   self.type = type

 }

// MARK: NSCoding
    required init?(coder decoder: NSCoder) {

       mapItem = decoder.decodeObject(forKey: "mapItem") as! MKMapItem?
       type = decoder.decodeObject(forKey: "type") as! Category?
    }

    func encode(with coder: NSCoder) {

      coder.encode(mapItem, forKey: "mapItem")
      coder.encode(type, forKey: "type")
    }

 }

但这行不通,因为 MKMapItem 不符合 NSCoding 标准(尽管编译器不会抱怨)。我确实了解如何对自定义类进行编码,但不知道如何对 iOS 已经定义的对象进行编码。

我知道 Objective-C 对此有一个答案,但我真的很想要一个 Swift 解决方案。谢谢。

PS 我已经尝试子类化 MKMapItem 并提供“新的”初始化程序,即使它需要在其他地方进行大量代码更改。但这会导致“无法分配给属性:'placemark' 是一个只能获取的属性”。 'placemark' 和 'isCurrentLocation' 都是 get-only。

import UIKit
import MapKit

class NewMapItem: MKMapItem {


    required init(placemark: MKPlacemark, isCurrentLocation:Bool, name: String,         phoneNumber: String, url: URL, timeZone: TimeZone) {
    self.placemark = placemark  //compiler complains "get-only"
    self.isCurrentLocation = isCurrentLocation  //compiler complains "get-only"
    self.name = name
    self.phoneNumber  = phoneNumber
    self.url = url
    self.timeZone = timeZone

}

// MARK: NSCoding

init?(coder decoder: NSCoder) {

    placemark = (decoder.decodeObject(forKey: "placemark") as! MKPlacemark?)! //compiler complains "get-only"
    isCurrentLocation = decoder.decodeBool(forKey: "isCurrentLocation")  //compiler complains "get-only"
    name = decoder.decodeObject(forKey: "name") as? String
    phoneNumber = decoder.decodeObject(forKey: "phoneNumber") as? String
    url = decoder.decodeObject(forKey: "url") as! URL?
    timeZone = decoder.decodeObject(forKey: "timeZone") as! TimeZone?
}

func encode(with coder: NSCoder) {

    coder.encode(placemark, forKey: "placemark")
    coder.encode(isCurrentLocation, forKey: "isCurrentLocation")
    coder.encode(name, forKey: "name")
    coder.encode(phoneNumber, forKey: "phoneNumber")
    coder.encode(url, forKey: "url")
    coder.encode(timeZone, forKey: "timeZone")
}
}

【问题讨论】:

    标签: swift mapkit nscoding


    【解决方案1】:

    我想通了。

    在“func encode(with coder: NSCoder)”中分解mapItem并在“init?(coder decoder: NSCoder)”中重新构建它

    我确实利用了带有地标的 MKMapItem 初始化程序。

       MKMapItem(placemark: placemark!)
    

    这是我的工人阶级:

    import UIKit
    import MapKit
    
    class Place: NSObject, NSCoding {
    
      var mapItem : MKMapItem!
      var type : Category!
    
      init(mapItem: MKMapItem, type: Category) {
        self.mapItem = mapItem
        self.type = type
      }
    
    // MARK: NSCoding
        required init?(coder decoder: NSCoder) {
    
        //liberate the properties of mapItem and rebuild it
        // let isCurrentLocation = decoder.decodeObject(forKey: "isCurrentLocation") as! Bool //don't need set already
          let name = decoder.decodeObject(forKey: "name") as! String?
          let phoneNumber = decoder.decodeObject(forKey: "phoneNumber") as! String?
          let url = decoder.decodeObject(forKey: "url") as! URL?
          let timeZone = decoder.decodeObject(forKey: "timeZone") as! TimeZone?
          let placemark = decoder.decodeObject(forKey: "placemark") as! MKPlacemark?
    
         self.mapItem = MKMapItem(placemark: placemark!)
         self.mapItem.name = name
         self.mapItem.url = url
         self.mapItem.phoneNumber = phoneNumber
         //self.mapItem.isCurrentLocation = isCurrentLocation //don't need this. Set already
         self.mapItem.timeZone = timeZone
    
         type = decoder.decodeObject(forKey: "type") as! Category?
    
       }
    
       func encode(with coder: NSCoder) {
         let placemark = mapItem.placemark
         let name = mapItem.name
         let phoneNumber  = mapItem.phoneNumber
         let url = mapItem.url
         let timeZone = mapItem.timeZone
    
         coder.encode(name, forKey: "name")
         coder.encode(phoneNumber,forKey: "phoneNumber")
         coder.encode(url, forKey: "url")
         coder.encode(timeZone, forKey: "timeZone")
         coder.encode(type, forKey: "type")
         coder.encode(placemark, forKey: "placemark")
    
       }
    
    }
    

    【讨论】:

      【解决方案2】:

      MKMapItem 使用 NSSecureCoding,因此您可以使您的类符合 NSSecureCoding,如下例所示,您不必重新创建 MKMapItem:

      class BGFPlaceItem: NSObject, NSSecureCoding {
          static var supportsSecureCoding: Bool {
              return true
          }
          func encode(with aCoder: NSCoder) {
              aCoder.encode(loadedAs.rawValue, forKey: "loadedAs")
              aCoder.encode(favorited, forKey: "favorited")
              aCoder.encode(mapItem, forKey: "mapItem")
          }
          required convenience init?(coder aDecoder: NSCoder) {
              let la = aDecoder.decodeObject(forKey: "loadedAs") as! String
              let fav = aDecoder.decodeBool(forKey: "favorited")
              let mi = aDecoder.decodeObject(forKey: "mapItem") as! MKMapItem
              let la2 = LoadedType(rawValue: la)!
              self.init(loadedAs: la2, isFavorited: fav, with: mi)
          }
          enum LoadedType: String {
              case generalPlace
              case favorite
              case searchResult
      
              var color: UIColor {
                  switch self {
                  case .generalPlace: return UIColor(named: "generalPlaceColor")!
                  case .favorite: return UIColor(named: "favoriteColor")!
                  case .searchResult: return UIColor.yellow
                  }
              }
          }
          var loadedAs: LoadedType
          var favorited: Bool
          var mapItem: MKMapItem
      
          init(loadedAs: LoadedType, isFavorited favorited: Bool, with mi: MKMapItem) {
              self.loadedAs = loadedAs
              self.favorited = favorited
              self.mapItem = mi
      
              super.init()
          }
      }
      

      【讨论】:

        【解决方案3】:

        你总是可以通过扩展它来使其兼容

        extension MKMapItem: NSCoding {
           required init?(coder decoder: NSCoder) {
               // codes
           }
        
           func encode(with coder: NSCoder) {
               // more codes
           }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多