- 函数式编程(Funtional Programming,简称FP),是一种编程范式,也就是如何编写程序的方法论
- 主要思想:把计算过程尽量分解成一系列可服用函数的的调用
- 主要特征:函数是“第一等公民”
- 函数与其他数据类型一样的地位,可以赋值给其他变量,也可以作为函数参数,函数返回值
函数合成
假设要实现以下功能:[(num + 3) *5 - 1] % 10 /2
let num = 1
func add(_ v:Int) ->(Int) ->Int {{$0 + v}}
func sub(_ v:Int) ->(Int) ->Int {{$0 - v}}
func multiple(_ v:Int) ->(Int) ->Int {{$0 * v}}
func divide(_ v:Int) ->(Int) ->Int {{$0 / v}}
func mod(_ v:Int) ->(Int) ->Int {{$0 % v}}
infix operator >>> : AdditionPrecedence
func >>><A,B,C>(_ f1:@escaping (A) -> B,
_ f2;@escaping (B) -> C) -> (A) ->C {{f2(f1($0))}}
var fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
fn(num)
高阶函数(Higher-Order Function) 高阶函数是至少满足下列一个条件的函数: 接受一个或多个函数作为输入(map、filter、reduce等) 返回一个函数
柯里化(Curring) 什么是柯里化? 将一个接受多参数的函数变换为一系列只接收单个参数的函数
func add(_ v1:Int,_ v2:Int) -> Int {v1 + v2}
add(10,20)
func add(_v:Int) ->(Int) -> Int{{$0 + v}}
add(10)(20)
Array,Optional的map方法接收的参数就是一个柯里化函数
func add2(_ v1:Int,_ v2: Int,_ v3:Int) -> Int{v1 + v2 + v3}
func add2(_ v3:Int) -> (Int) ->(Int) -> Int {
// v2 == 20
return { v2 in
// v1 == 10
return { v1 in
return v1 + v2 + v3
}
}
}
add2(30)(20)(10)
func add(_ v1:Int,_ v2:Int) -> Int {v1 + v2}
func sub(_ v1:Int,_ v2:Int) -> Int {v1 - v2}
func multiple(_ v1:Int,_ v2:Int) -> Int {v1 * v2}
func divide(_ v1:Int,_ v2:Int) -> Int {v1 / v2}
func mod(_ v1:Int,_ v2:Int) -> Int {v1 % v2}
func currying<A,B,C>(_ fn:@escaping (A,B) ->C) ->(B) -> (A) -> C {
return { b in
return { a in
return fn(a,b)
}
}
}
print(currying(add)(20)(100))
print(currying(sub)(20)(100))
print(currying(multiple)(20)(100))
print(currying(divide)(20)(100))
print(currying(mod)(20)(100))
prefix func ~<A,B,C>(_ fn:@escaping (A,B) ->C) ->(B) ->(A) -> C {
{b in {a in fn(a.b)}}
}
print((~sub)(20)(10))
面向协议编程
面向协议编程(Protocol Oriented Programming,简称POP),是Swift的一种编程范式 同时,Swift也是一门面向对象的编程语言(Object Oriented Programming,简称OOP),在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方。 OOP 的三大特性:封装、继承、多态
POP的解决方案
protocol Runnable {
func run()
}
extension Runnable {
fun run(){
print("run")
}
}
class BVC:UIViewController,Runnable {}
class DV:UITableViewController,Runnable {}
POP 的注意点
优先考虑创建协议,而不是父类(基类) 优先考虑值类型(struct、enum)、而不是引用类型(class) 巧用协议的扩展功能 不要为了面向协议而使用协议。
利用协议实现前缀效果
// 前缀类型
struct JG<Base> {
var base:Base
init(_ base:Base){
self.base = base
}
}
// 利用协议扩展前缀属性
protocol JGCompatible {}
protocol JGCompatible{
var jg:JG<Self> {JG(self)}
static var jg:MJ<Self>.Type {MJ<Self>.self}
}
// 给字符串扩展功能
// 让String 拥有jg前缀属性
extension String : JGCompatible{}
class Person {}
extension Person : JGCompatible{}
struct Dog {}
extension Dog : JGCompatible{}
// 给String.jg 、String().jg前缀扩展功能
//extension JG where Base == String {
// var numberCount:Int {
// var count = 0
// for c in base where ("0"..."9").contains(c) {
// count += 1
// }
// return count
// }
// static func test (){
// }
//}
// String,NSString 都遵守ExpressibleByStringLiteral,只要遵守这个协议的都可以使用
extension JG where Base :ExpressibleByStringLiteral {
var numberCount:Int {
var count = 0
for c in base as! String where ("0"..."9").contains(c) {
count += 1
}
return count
}
static func test (){
}
}
// : 代表Person及Person子类都拥有这个方法
extension JG where Base:Person {
func run() {
print("run")
}
}
print("123kkkk".jg.numberCount)
var person = Person()
person.jg.run()
String.jg.test()
利用协议实现类型判断
func isArray(_ value:Any) -> Bool {value is [Any]}
isArray([1,2])
isArray(["1",2])
isArray(NSArray)
isArray(NSMutableArray())
protocol ArrayType {}
extension Array:ArrayType {}
extension NSArray:ArrayType {}
func isArrayType(_ type:Any.Type) -> Bool {
//type is [Any].Type
type is ArrayType.Type
}
isArrayType([Int].self)
isArrayType([Any].self)
isArrayType(NSArray.self)
isArrayType(NSMutableArray.self)
响应式编程
- 响应式编程(Reactive Programming,简称RP),一种编程范式,可以简化异步编程,提供更优雅的数据绑定
- 一般与函数式融合在一起,所以也会叫做:函数响应式编程(Functional Reactive Programming,简称FRP)
RxSwift的核心角色
- Observable:负责发送事件(Event)
- Observer:负责订阅Observable,监听Observable发送的事件(Event)
事件(Event)有3种
public enum Event<Element> {
case next(Element)// 携带具体数据
case error(Swift.Error) // 携带错误信息,表明Observable终止,不会再发出事件
case completed //表明Observable终止,不会再发出事件
}
创建、订阅Observable1
var observable = Observable<Int>.create { observer in
observer.onNext(1)
observer.onCompleted()
return Disposablees.create()
}
// 等价于
observable = Observable.just(1)
observable = Observable.of(1)
observable = Observable.from([1])
Disposable 每当Observable被订阅时,都会返回一个Disposable实例,当调用Disposable的dispose,就相当于取消订阅 在不需要再接收事件时,建议取消订阅,释放资源。有三种常见方式取消订阅
// 立即取消订阅(一次性订阅)
observable.subscribe{event in print(event)}.dispose()
// 当bag销毁(deinit)时,会自动调用Disposable实例的dispose
let bag = DisposeBag()// 控制器销毁了,就销毁啦
observable.subscribe{event in print(event)}.dispose(by:bag)
// self销毁时(deinit)时,会自动调用Disposable实例的dispose
let _ = observable.takeUntil(self.rx.deallocated).subscribe{
event in print(event)
}
创建Observer
let observer = AnyObserver<Int>.init{ event in
switch event {
case .next(let data):print(data)
case .completed:print("completed")
case .error(let error):print("error",error)
}
}
observable.just(1).subscribe(observer).dispose()
let binder = Binder<String>(label){label,text in label.text = text}
Observable.just(1).map{"数值是\($0)"}.subscribe(binder).dispose()
Observable.just(1).map{"数值是\($0)"}.bind(to:binder).dispose()
传统的状态监听 在开发中经常要对各种状态进行监听,传统的常见监听方案有
Rxswift
button.rx.tap.subscribe(onNext:{
print("按钮被点击了1")
}).disposed(by:bag)
let data = Observable.just([Person(name:"Jack",age:10),Person(name:"Rose",age:20)])
data.bind(to:tableView.rx.items(cellIdentifier:"cell")){
row,person,cell in
cell.textLabel?text = person.name
cell.detailTextLabel?.text = "\(person.age)"
}
tableView.rx.modelSelected(Person.self).subscribe(
onNext:{ person in print("点击了",person.name)}).disposed(by:bag)
状态监听2
class Dog:NSObject {
@objc dynamic var name:String?
}
dog.rx.observe(String.self,"name")
.subscribe(onNext:{name in print("name is",name ?? "nil")})
.disposed(by:bag)
dog.name = "larry"
dog.name ="wangwang"
通知监听
NotificationCenter.default.rx
.notification(UIApplication.didEnterBackgroundNotification)
.subscribe(onNext:{notification in print("APP 进入后台",notification)})
.disposed(by:bag)
即是Observale,又是Observer
Observeable.just(0.8).bind(to:slider.rx.value).disposed(by:bag)
slider.rx.value.map {
"当前数值是:\($0)"
}.bind(to:textField.rx.text).disposed(by:bag)
textField.rx.text.subscript(onNext:{text in print("text is",text ?? "nil")}).disposed(by:bag)