问题描述
在Xcode代码中,尝试使用print输出相关信息报错。
代码内容:
print("2、inputRadius:\(filter.attributes["inputRadius"]?["CIAttributeDefault"] ?? 0)")
报错内容:
Value of type 'Any' has no subscripts
报错原因:
open class CIFilter : NSObject, NSSecureCoding, NSCopying {
...
open var attributes: [String : Any] { get }
}
因为 filter.attributes[“inputRadius”] 返回的是一个 Any? 类型的值,而 Swift 不允许直接对 Any 类型进行下标操作。为了访问其中嵌套的键值对,需要先将它强制转换为适当的类型,比如 [String: Any]。
解决方案
解决代码:
if let inputRadiusAttributes = filter.attributes["inputRadius"] as? [String: Any] {
let defaultValue = inputRadiusAttributes["CIAttributeDefault"] ?? "nil"
print("2、inputRadius: \(defaultValue)")
} else {
print("2、inputRadius: nil")
}
问题分析
上面的问题主要涉及返回值类型的转换,filter.attributes 本身是 [String: Any] 类型, 但是当通过键访问字典时,比如:
filter.attributes["inputRadius"] // return Any?
Swift 返回的是 Any?因为:
1、键值对中的值可以是任何类型。
2、键可能不存在,返回值因此是可选的。
为了安全地操作 filter.attributes[“inputRadius”] 的内容,我们需要将其从 Any? 转换为 [String: Any] 类型。
为什么需要 as? [String: Any]
filter.attributes[“inputRadius”] 返回的值是 Any?,我们需要确认它是否是一个 [String: Any] 类型的字典并安全地解包,以便进一步访问内部的键值。通过 as? [String: Any],我们可以:
1、确认类型:
如果值确实是 [String: Any],转换成功并返回对应的字典。
let inputRadiusAttributes = filter.attributes["inputRadius"] as? [String: Any]
2、避免运行时错误:
如果值不是 [String: Any] 类型,as? 返回 nil,代码不会崩溃。
if let inputRadiusAttributes = filter.attributes["inputRadius"] as? [String: Any] {
// 安全访问字典内容
} else {
// 无法转换,安全处理
}
3、为什么不能直接当作 [String: Any] 使用?
因为编译器不知道 filter.attributes[“inputRadius”] 的类型就是 [String: Any],即使已经“知道”它的类型也不能直接使用。Swift 类型系统是严格的,要求开发者明确声明和检查类型以避免潜在的类型错误。
直接转换问题
如果尝试直接转换代码:
filter.attributes["inputRadius"]["CIAttributeDefault"] as? [String: Any][String]
就会遇到如下报错:
Array types are now written with the brackets around the element type
Replace '[String: Any][' with '[[String: Any]'
Value of type 'Any?' has no subscripts
原因为:filter.attributes[“inputRadius”] 返回的是 Any?,不能直接用 [“CIAttributeDefault”] 访问其内部值。Swift 不允许对 Any? 类型直接进行下标操作。
此外,as? [String: Any][String] 是非法语法。在 Swift 中,as? 后面必须是一个合法的单一类型。[String: Any][String] 并不是一个合法的类型声明。所以应该拆成两步:
1、将 filter.attributes[“inputRadius”] 转换为 [String: Any]。
2、从 [String: Any] 中访问 CIAttributeDefault 的值。
对下标嵌套的误用
filter.attributes["inputRadius"]["CIAttributeDefault"]
filter.attributes[“inputRadius”] 直接使用下标访问 [“CIAttributeDefault”]。但 filter.attributes[“inputRadius”] 是 Any? 类型,无法直接下标操作,必须显式解包和类型转换。