【问题标题】:Create array of non-nil properties of a class in Swift 4在 Swift 4 中创建类的非零属性数组
【发布时间】:2018-05-09 14:05:20
【问题描述】:

我创建了一个包含所有可选属性的类。我正在尝试创建一个计算的var,它返回对象的所有非零属性。

[<array of stuff>].flatMap{ $0 } 似乎是显而易见的选择,但是当我在 Playground 中对其进行修改时,它仍然返回一个包含 nil 值的数组。

以下是我尝试获取类的非零属性数组的各种迭代:

假设我这样声明我的对象:

let lastSearch = LastSearch(startDate: startDate, endDate: endDate, minMagnitude: 1.0, maxMagnitude: 5.0, minLongitude: nil, maxLongitude: nil, minLatitude: nil, maxLatitude: nil, minDepth: nil, maxDepth: nil)

尝试 #1: 在我的课堂上,我正在尝试创建一个 nonNilProperties 计算变量:

var nonNilProperties: Any {
    return [startDate, endDate, minMagnitude, maxMagnitude, minLongitude, maxLongitude, minLatitude, maxLatitude, minDepth , maxDepth].flatMap{ $0 } as Any
}

这是我打印 lastSearch.nonNilProperties 时在控制台中打印的内容:

[Optional(2015-10-01 13:23:32 +0000), Optional(2015-10-07 01:43:59 +0000), Optional(1.0), Optional(5.0), nil, nil, nil, nil, nil, nil]

尝试 #2:

如果我在每个属性后添加as Any,它会消除编译器警告,并且填充的值不会在它们前面打印“可选”,但它仍然有null 值:

var nonNilProperties: Any {
    return [startDate as Any, endDate as Any, minMagnitude as Any, maxMagnitude as Any, minLongitude as Any, maxLongitude as Any, minLatitude as Any, maxLatitude as Any, minDepth as Any, maxDepth as Any].flatMap{ $0 } as [AnyObject]
}

这是我打印时在控制台中打印的内容:

[2015-10-01 13:23:32 +0000, 2015-10-07 01:43:59 +0000, 1, 5, <null>, <null>, <null>, <null>, <null>, <null>]

感谢您的阅读。我欢迎你的建议。下面是这个类的样子:

class LastSearch {

  private var startDate: Date?
  private var endDate: Date?
  private var minMagnitude: Double?
  private var maxMagnitude: Double?
  private var minLongitude: Double?
  private var maxLongitude: Double?
  private var minLatitude: Double?
  private var maxLatitude: Double?
  private var minDepth: Double?
  private var maxDepth: Double?

  private var nonNilProperties: Any {
    return [startDate as Any, endDate as Any, minMagnitude as Any, maxMagnitude as Any, minLongitude as Any, maxLongitude as Any, minLatitude as Any, maxLatitude as Any, minDepth as Any, maxDepth as Any].flatMap{ $0 } as Any
  }

  init(startDate: Date?, endDate: Date?,
       minMagnitude: Double?, maxMagnitude: Double?,
       minLongitude: Double?, maxLongitude: Double?,
       minLatitude: Double?, maxLatitude: Double?,
       minDepth: Double?, maxDepth: Double?) {
    // Dates
    self.startDate = startDate
    self.endDate = endDate

    // Magnitude Values
    self.minMagnitude = minMagnitude
    self.maxMagnitude = maxMagnitude

    // Geographic Coordinates
    self.minLongitude = minLongitude
    self.maxLongitude = maxLongitude
    self.minLatitude = minLatitude
    self.maxLatitude = maxLatitude

    // Depth Values
    self.minDepth = minDepth
    self.maxDepth = maxDepth
  }      
}

【问题讨论】:

  • 为什么要创建一个所有属性都可能为零的类?您确定需要将它们全部设为可选项吗?
  • 如果没有初始化属性之一,该类将永远不会被初始化。我正在使用班级在班级之间进行簿记。它有一些我没有在这里发布的方法。
  • 顺便说一句,您如何知道要使用数组中的哪些元素以及如何识别它们是哪些?我认为这没有用。
  • @LeoDabus 我想了一个办法,认为它超出了这个问题的范围。
  • 另一种方法return ((Mirror(reflecting: self).children.map { $0.value } as [Any]) as [Any?]).flatMap { $0 }

标签: ios swift computed-properties


【解决方案1】:

一种解决方案是显式创建一个[Any] 类型的新数组,并且仅在不是nil 时才将属性添加到数组中。

public var nonNilProperties: [Any] {
    let allProperties: [Any?] = [startDate, endDate, minMagnitude, maxMagnitude, minLongitude, maxLongitude, minLatitude, maxLatitude, minDepth, maxDepth]
    var output = [Any]()
    for property in allProperties {
        if let nonNilProperty = property {
            output.append(nonNilProperty)
        }
    }
    return output
}

或者您可以使用更接近原始解决方案的flatMap(感谢@Leo Dabus)

public var nonNilProperties: [Any] {
     return ([startDate, endDate, minMagnitude, maxMagnitude, minLongitude, maxLongitude, minLatitude, maxLatitude, minDepth, maxDepth] as [Any?]).flatMap { $0 }
}

测试用例:

let lastSearch = LastSearch(startDate: Date(), endDate: Date(), minMagnitude: 1.0, maxMagnitude: 5.0, minLongitude: nil, maxLongitude: nil, minLatitude: nil, maxLatitude: nil, minDepth: nil, maxDepth: nil)
print(lastSearch.nonNilProperties)

输出:

[2017-11-26 02:00:13 +0000, 2017-11-26 02:00:13 +0000, 1.0, 5.0]

这可行,但有点尴尬。根据您的具体情况,可能有更好的方法来构建您的数据。

【讨论】:

  • 仍然返回选项
  • @LeoDabus 我明白你在说什么。我会很快编辑我的答案。
  • 您可以将数组类型显式设置为[Any?],而不是强制转换。 let allProperties: [Any?] = [startDate, endDate, minMagnitude, maxMagnitude, minLongitude, maxLongitude, minLatitude, maxLatitude, minDepth, maxDepth]
  • 顺便说一句return ([startDate, endDate, minMagnitude, maxMagnitude, minLongitude, maxLongitude, minLatitude, maxLatitude, minDepth, maxDepth] as [Any?]).flatMap{$0}
【解决方案2】:

第一个 nonNilProperties 不是 Any,它的 [Any](任意数组)。而且您不需要将每个属性都转换为任何属性,它会自动执行此操作。其次, flatMap 不是您所需要的。使用地图。 flatMap 不会遍历元素,而是对整个数组进行操作。以下是一些示例:http://sketchytech.blogspot.ru/2015/06/swift-what-do-map-and-flatmap-really-do.html

【讨论】:

    【解决方案3】:

    正如 Leo Dabus 在 cmets 中指出的那样,如果我不知道它们是什么,那么单独拥有非 nil 值是没有用的。也就是说,这就是我最终所做的:

    Charles Prince's 的回答中,我找到了一种解包选项的方法。

    我将此方法添加到我的班级:

    func unwrap<T>(_ any: T) -> Any {
      let mirror = Mirror(reflecting: any)
      guard mirror.displayStyle == .optional, let first = mirror.children.first else {
        return any
      }
      return unwrap(first.value)
    }
    

    然后,我创建了一个计算 var 以返回非零值的 Dictionary,使用 Mirror 获取键和值。

    var nonNilPropertyDict: [String: Any] {
    
        let keys = Mirror(reflecting: self).children.flatMap { $0.label }
        let values = Mirror(reflecting: self).children.flatMap { unwrap($0.value) as! AnyObject }
    
        var dict = Dictionary(uniqueKeysWithValues: zip(keys, values))
    
        var keysToRemove = dict.keys.filter{ dict[$0] is NSNull }
        for key in keysToRemove {
          dict.removeValue(forKey: key)
        }
    
        return dict
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      • 2020-09-04
      • 1970-01-01
      • 2019-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多