当前位置: 首页 > 面试题库 >

可选字段类型不符合Swift 3中的协议

岳迪
2023-03-14
问题内容

我有一个带有1个可选字段和1个非可选字段的类,它们都具有Type AnotherClass 类型,并且还符合
CustomProtocol

protocol CustomProtocol {}

class CustomClass: CustomProtocol {

    var nonoptionalField: AnotherClass = AnotherClass()
    var optionalField: AnotherClass?

}

class AnotherClass: CustomProtocol {

}

现场 nonoptionalField 的类型 AnotherClass 和符合 CustomProtocol

另一方面, optionalField 实际上是 Optional ,因此不符合
CustomProtocol

for field in Mirror(reflecting: CustomClass()).children {
    let fieldMirror = Mirror(reflecting: field.value)
    if fieldMirror.subjectType is CustomProtocol.Type {
        print("\(field.label!) is \(fieldMirror.subjectType) and conforms CustomProtocol")
    } else {
        print("\(field.label!) is \(fieldMirror.subjectType) and DOES NOT conform CustomProtocol")
    }
}
// nonoptionalField is AnotherClass and conforms CustomProtocol
// optionalField is Optional<AnotherClass> and DOES NOT conform CustomProtocol

如何解开 optionalField 属性的Type(而不是值),以便可以将其与其协议 CustomProtocol 关联?

换句话说,如何从 Optional 类型中获取包装 好的 Type
AnotherClass __

局限性:

我真的必须通过镜像使用Swift反射,不幸的是, 到目前为止,.subjectType 属性不允许解开 Optional
的可选包装类型。


问题答案:

我不认为有一种简单的方法来执行此操作,因为我们目前无法在没有占位符的情况下就泛型类型进行交谈-因此我们不能简单地转换为Optional.Type

我们Optional<Any>.Type也不能转换为,因为编译器无法为其提供实例的元类型值提供相同类型的自动转换(例如An
Optional<Int>可以转换为an Optional<Any>,而an Optional<Int>.Type不能转换为a
Optional<Any>.Type)。

然而,一种解决方案(尽管有些棘手)将是定义一个“虚拟协议”以表示“任何Optional实例”,而与Wrapped类型无关。然后,我们可以让该协议定义一个wrappedType要求,以便获得Wrapped给定Optional类型的元类型值。

例如:

protocol OptionalProtocol {
  // the metatype value for the wrapped type.
  static var wrappedType: Any.Type { get }
}

extension Optional : OptionalProtocol {
  static var wrappedType: Any.Type { return Wrapped.self }
}

现在,如果fieldMirror.subjectTypeOptional<Wrapped>.Type,我们可以将其转换为OptionalProtocol.Type,然后从中获取元wrappedType类型值。然后,这使我们可以检查CustomProtocol一致性。

for field in Mirror(reflecting: CustomClass()).children {
  let fieldMirror = Mirror(reflecting: field.value)

  // if fieldMirror.subjectType returns an optional metatype value
  // (i.e an Optional<Wrapped>.Type), we can cast to OptionalProtocol.Type,
  // and then get the Wrapped type, otherwise default to fieldMirror.subjectType
  let wrappedType = (fieldMirror.subjectType as? OptionalProtocol.Type)?.wrappedType
    ?? fieldMirror.subjectType

  // check for CustomProtocol conformance.
  if wrappedType is CustomProtocol.Type {
    print("\(field.label!) is \(fieldMirror.subjectType) and conforms CustomProtocol")
  } else {
    print("\(field.label!) is \(fieldMirror.subjectType) and DOES NOT conform CustomProtocol")
  }
}

// nonoptionalField is AnotherClass and conforms CustomProtocol
// optionalField is Optional<AnotherClass> and conforms CustomProtocol

这仅处理单个级别的可选嵌套,但可以通过简单地反复尝试将结果元类型值强制转换为OptionalProtocol.Type并获取wrappedType,然后检查CustomProtocol一致性来轻松地应用于任意可选嵌套级别。

class CustomClass : CustomProtocol {
    var nonoptionalField: AnotherClass = AnotherClass()
    var optionalField: AnotherClass??
    var str: String = ""
}

/// If `type` is an `Optional<T>` metatype, returns the metatype for `T`
/// (repeating the unwrapping if `T` is an `Optional`), along with the number of
/// times an unwrap was performed. Otherwise just `type` will be returned.
func seeThroughOptionalType(
  _ type: Any.Type
) -> (wrappedType: Any.Type, layerCount: Int) {

  var type = type
  var layerCount = 0

  while let optionalType = type as? OptionalProtocol.Type {
    type = optionalType.wrappedType
    layerCount += 1
  }
  return (type, layerCount)
}

for field in Mirror(reflecting: CustomClass()).children {

  let fieldMirror = Mirror(reflecting: field.value)
  let (wrappedType, _) = seeThroughOptionalType(fieldMirror.subjectType)

  if wrappedType is CustomProtocol.Type {
    print("\(field.label!) is \(fieldMirror.subjectType) and conforms CustomProtocol")
  } else {
    print("\(field.label!) is \(fieldMirror.subjectType) and DOES NOT conform CustomProtocol")
  }
}
// nonoptionalField is AnotherClass and conforms CustomProtocol
// optionalField is Optional<Optional<AnotherClass>> and conforms CustomProtocol
// str is String and DOES NOT conform CustomProtocol


 类似资料:
  • 问题内容: 编译错误如下: 类型“ AnyObject”不符合协议“ SequenceType” 这种压力是什么? 谁能帮我很多忙! 问题答案: 苹果在Swift编程语言中指出: for-in循环针对范围,序列,集合或进度中的每个项目执行一组语句。 目前,它仅符合protocol ,因此您无法在其上使用for循环。如果要这样做,则必须执行类似以下操作:

  • 问题内容: Beta 3一切正常,现在出现一个奇怪的错误,而且我不知道如何解决它。尝试了所有类似问题的解决方案。 这是我的代码: 两条标记线都给了我相同的错误: 类型“ String.Index”不符合协议“ IntegerLiteralConvertible” 有人能帮我吗?还是Beta 4有漏洞?谢谢! 问题答案: 在Beta 4中,Swift的String.Index处理再次发生了变化- 现

  • 问题内容: 尝试按照Apple文档(和教程化的)创建Launch Helper时,我似乎遇到了麻烦,原因是将Objective- C代码移植到Swift中…在此方面,谁的编译器再也不过分了案件。 该错误似乎始终是: 我尝试过在多个位置进行转换,以防万一我只是在处理一个多余的,古老的原语(由Obj- C或Core Foundation引入)而无济于事。 为了以防万一,我尝试投射响应: 产生错误: …

  • 最后一点:如果这似乎与SO上的其他问题重复,我道歉。如前所述,我已经看了他们,但无法得到我想要的理解。

  • 问题内容: 作为学习的练习,我将在Swift中重写我的验证库。 我有一个协议定义了各个规则的外观: 关联的类型定义要验证的输入的类型(例如,字符串)。它可以是显式的或通用的。 这是两个规则: 在其他地方,我有一个函数,用于验证带有s 集合的输入: 我以为这行得通,但是编译器不同意。 在下面的例子中,即使输入是一个字符串,的是一个字符串,并且Ş 是一个String … …我收到了非常有用的错误消息:

  • 问题内容: 我有一个符合多种协议的Objective-C变量。 我将如何在Swift中代表这种类型? 问题答案: 这应该工作: 注意,必须快速使用NSObjectProtocol而不是NSObject。 以下是一些其他示例: 符合多种协议的对象数组: 具有符合多种协议的参数的功能: 对于3.1之前的Swift版本,请使用: