Swift显式声明CIFilter以适配所有滤镜类型
Swift显式声明CIFilter以适配所有滤镜类型

Swift显式声明CIFilter以适配所有滤镜类型

本文主要讲解在实际应用中,为什么在提供通用的滤镜支持时,应该考虑显式声明CIFilter。

隐式类型推断

下面是一个隐式类型推断的sepiaTone(棕褐色调滤镜):

struct ContentView: View {
    @State private var currentFilter = CIFilter.sepiaTone()
    func applyProcessing() {
        currentFilter.intensity = Float(filterIntensity)
        ...
    }
...
}

隐式类型推断

在这种情况下,Swift 会根据右侧的初始化值 CIFilter.sepiaTone() 自动推断 currentFilter 的类型。

因为 CIFilter.sepiaTone() 返回的是具体的 CISepiaTone 类型,currentFilter 的类型将被推断为 CISepiaTone。

访问具体滤镜的特性

这种写法允许直接访问 CISepiaTone 的特定属性(如 .intensity),而不需要再进行类型转换。

currentFilter.intensity = Float(filterIntensity)

用途

如果确定 currentFilter 始终是 CISepiaTone 类型,并需要直接操作其特定属性(如 intensity),这种写法更方便。

如果需要更通用的滤镜支持,可以显式声明 currentFilter 为 CIFilter 类型,但这样会失去对特定协议属性(如 intensity)的直接访问。

显式声明

@State private var currentFilter:CIFilter = CIFilter.sepiaTone()

显式声明类型为 CIFilter

在这种情况下,currentFilter 的类型是明确设定为 CIFilter。

即使 CIFilter.sepiaTone() 实际上是一个 CISepiaTone 类型的实例,它会被 向上转型 为通用的 CIFilter 类型。

这是 Swift 的 多态特性,允许子类实例(CISepiaTone)被赋值为父类类型(CIFilter)

类型约束明确

后续代码中,currentFilter 只能使用 CIFilter 公共接口,无法直接访问 CISepiaTone 的专有属性(如 .intensity)。

currentFilter.intensity = Float(filterIntensity)    // 不再可用

因此应该考虑使用setValue替代intensity属性的访问。

currentFilter.setValue(filterIntensity, forKey: kCIInputIntensityKey)

用途

适合需要动态切换滤镜类型的场景,比如通过按钮切换 CIFilter.sepiaTone() 和 CIFilter.gaussianBlur() 等不同滤镜类型。

为什么不能动态改变类型?

可能有人会疑惑,既然可以进行隐式类型推断,那么给CIFilter赋值新的滤镜,CIFilter也应该能重新推断类型,为什么还有显式声明为CIFilter类型。

虽然 Swift 的类型推断很强大,但对于属性(如 @State)的类型,类型一旦确定就不能在运行时动态改变。这是因为 Swift 是一门强类型语言,所有属性的类型在编译时就已经固定。

当声明 @State private var currentFilter = CIFilter.sepiaTone() 时:

1、类型推断结果是 CISepiaTone

这是因为 CIFilter.sepiaTone() 返回一个 CIFilter 实例,且遵循了 CISepiaTone 协议。

2、Swift 在编译时确定了 currentFilter 的类型为 CISepiaTone

这意味着之后无论赋值为其他滤镜类型,如 CIFilter.gaussianBlur(),它都需要兼容 CISepiaTone 协议。

赋值新滤镜时的问题

如果尝试以下代码:

currentFilter = CIFilter.gaussianBlur()

此时会报错,原因是 CIFilter.gaussianBlur() 返回的类型是 CIGaussianBlur,它与 CISepiaTone 协议不兼容。即使两者都是 CIFilter 的子类,它们遵循的是不同的滤镜协议,Swift 不允许隐式类型更改

报错内容为:

Value of type 'any CIFilter & CIGaussianBlur' does not conform to 'CISepiaTone' in assignment

如何解决?

如果需要在运行时切换不同类型的滤镜,应该将 currentFilter 显式声明为 CIFilter,例如:

@State private var currentFilter: CIFilter = CIFilter.sepiaTone()

在这种情况下:

1、currentFilter 的类型被固定为 CIFilter,是一个通用的滤镜类型。

2、在赋值新滤镜时:

currentFilter = CIFilter.gaussianBlur()

这是合法的,因为 CIFilter 是所有滤镜的基类。

为什么推荐显式声明为 CIFilter?

显式声明为 CIFilter 可以让的代码在切换滤镜时更加灵活:

可以动态更改滤镜类型。

不需要为每个滤镜分别声明对应的类型协议。

不过,缺点是会失去协议中方便的类型安全支持(如 CISepiaTone.intensity),必须通过 setValue(_:forKey:) 和 value(forKey:) 来设置和获取参数。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注