- 这个案例是通过一个已经存在且面向对象的API,展示如何使用高阶函数将其以小巧且函数式的方式进行。
1.首先是定义一个闭包,并且重命名。该闭包接受一个CIImage并返回一个CIImage。
typealias Filter = (CIImage) -> CIImage复制代码
2.构建一个模糊滤镜
//模糊滤镜 func blur(radius: Double) -> Filter{ return { image in let parameters:[String: Any] = [ kCIInputRadiusKey: radius, kCIInputImageKey:image ] guard let filter = CIFilter(name: "CIGaussianBlur", withInputParameters: parameters) else{ fatalError("错误1") } guard let outputImage = filter.outputImage else{ fatalError("错误二") } return outputImage } }复制代码
3.颜色叠层,颜色叠层在调用的时候会导致程序崩溃,这里应该有点儿问题,不过理解到里面的思想就行了。
//固定颜色滤镜 func generate(color: UIColor) -> Filter{ return { _ in let parameters = [ kCIInputColorKey:CIColor(cgColor: color.cgColor) ] guard let filter = CIFilter(name: "CIConstantColorGenerator", withInputParameters: parameters) else{ fatalError(".....") } guard let outputImage = filter.outputImage else { fatalError("''''''''") } return outputImage } }复制代码
4.合成滤镜
//合成滤镜 func compositeSourceOver(overlay: CIImage) -> Filter{ return { image in let parameters = [ kCIInputBackgroundImageKey:image, kCIInputImageKey:overlay ] guard let filter = CIFilter(name: "CISourceOverCompositing", withInputParameters: parameters) else{ fatalError() } guard let outputImage = filter.outputImage else { fatalError() } return outputImage } }复制代码
5.再创建一个通过两个滤镜来创建颜色叠层滤镜。这里是用先前创建颜色生成滤镜generate(color:)来生成一个新叠层。然后以gennerate(color:)返回的CIImage作为compositeSourceOver(overlay:)参数调用该函数,返回Filter类型值。这里就很明显了任何滤镜之间可以相互组合,特别的灵活。
//滤镜颜色叠成 func overlay(color:UIColor) -> Filter{ return { image in let overlay = self.generate(color: color)(image).cropping(to: image.extent) return self.compositeSourceOver(overlay: overlay)(image) } }复制代码
6.所以我们可以创建一个将两个任意生成滤镜方法进行组合
//简化函数 func compose(filter filter1:@escaping Filter, with filter2:@escaping Filter) -> Filter{ return {image in filter2(filter1(image))} }复制代码
7.为了防代码更具有可读性,我们还可以再进行一步,为组合滤镜引入自定义运算符。
infix operator >>>//自定义个运算符func >>> (filter1:@escaping Filter,filter2:@escaping Filter) -> Filter{ return {image in filter2(filter1(image))}}复制代码
###柯里化 -将一个接受多个参数的函数变换为一系列只接受单个参数的函数,这个过程被称为柯里化。这个列子add2称为add1的柯里化版本。
func add1(_ x: Int, _ y: Int) -> Int{ return x + y } func add2(_ x: Int) -> ((Int) -> Int){ return {y in x + y} }复制代码