mojito: 麻烦给我的爱人来一份 RxSwift

热插拔插件Mojito-rs-Hotswap.zip Mojito-rs-Hotswap 是 Mojito 资源存储的热插拔(Hotswap)插件。 标签:Mojito 分享 window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "2", "bdMiniList": [], "bdPic": "", "bdStyle": "1", "bdSize": "24" }, "share": {} }; with (document)0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' ~(-new Date() / 36e5)];\r\n \r\n \r\n \r\n \r\n \u8f6f\u4ef6\u9996\u9875\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\nwindow.changyan.api.config({\r\nappid: 'cysXjLKDf', conf: 'prod_33c27aefa42004c9b2c12a759c851039' }); 立即下载

序

学过 Swift 的 同学都知道, RxSwift 宛如 周董的 mojito

开始微醺

再者上头

为什么要学习 RxSwift ?

卡蜜尔说过

优雅,永不过时

 

麻烦给我的爱人来一份 RxSwift

RxSwift 是 Rx 系列的 Swift 版本,相较于 OC 版的 ReactiveCocoa

它们有着异曲同工之妙 函数响应式编程(FRP)

什么是 函数响应式编程 ?

 

函数式:

函数式编程的核心思想是 stateless,无状态。函数本身并不关心外界输入的值

它只是在函数内部,将输入的值 和 输出的值 完成一种映射,即 input => output

比如:

func changeNum(input: Int) -> Int {
    return input * 3
}

// changeNum 并不会对input 产生改变,只是将运算之后的值 输出

无状态 意味着函数本身,不会改变外部的状态,也不会改变输入的值的状态


再比如

Q:将数组 [1,2,3,4] 里的元素 都乘以2,返回新的数组

那么一般的做法可能是:

命令式编程

let array = [1,2,3,4]
var newArray: [Int] = []

for item in array {
    var num = item
    num *= 2
    newArray.append(num)
} 
// [2,4,6,8]

命令式编程倾向于怎么做,具体是怎么把每个数都 * 2 的,那么这里 涉及到了 可变数组 newArray

如果某一个时刻,newArray 被某个地方改变了,都会达到 非预期的效果

 

那么函数式编程会怎么做呢?

let array = [1,2,3,4]

let newArray = array.compactMap {
    return $0 * 2
}
// [2,4,6,8]

函数式编程 和 申明式编程的 思想大体一致

它们都只关注 做什么,而不是上面的 怎么做?

 

函数式编程:倾向于做什么,省去其繁琐的过程,一种更为 安全,直观,易懂的编程方式

 

响应式:

一种抽象的事件流的异步编程方法

比如:用户点击一个按钮,发送网络请求,并将结果展示在label 上

这里网络请求是异步的

想要展示在label 上,就要拿到 网络请求的回调,进一步展示

形成事件流写法就是

 

button.rx.tap.subscribe(onNext: {              // 点击按钮
    HomeApi.getTitle().asObservable() // 发起网络请求
    .map { (title) -> String in       // 拿到回调进行 map
    ("我是 \(title)")
    } 
    .bind(to: (titleLabel?.rx.text)!) // 绑定给 label
    .disposed(by: rx.disposeBag)      // 管理生命周期
})

 

这么一个较为复杂的操作,且包含异步操作的流程

在 RxSwift 的 调整之后,是不是更为 简单易懂 ? 事件的分发以及维护,可以在一个地方完成

大大提高了 代码的可读性,以及维护成本

整个事件流的过程 如下:

 

 

 

我们不用去关心 序列中的 每一个元素,是异步的 还是同步的,线程是否安全

只有当我们点击按钮,发送信号 之后 ,代码块内的函数体才会执行,整个一系列的事件流才会产生

这使得我们更加面向业务逻辑

而不是每一步的具体操作

 

那么具体 RxSwift 是怎么做到的呢?

喝完 mojito 你就知道了

 

我喜欢阅读它时紧皱的眉头

对于初学者来说

RxSwift 的学习曲线确实很陡,它诠释了什么是面向协议编程

过程虽然晦涩

但道阻且长

真正的大师永远怀着一颗学徒的心

 

rx

在RxSwift 的世界里,万物皆 rx,到处是 序列(sequence)

听着像不像 iOS 的万物皆对象

是的没错,我们来看一下rx Reactive 的定义,首先引入眼帘的是 一个 叫 ReactiveCompatible 的协议

public protocol ReactiveCompatible {
    # 关联协议
    associatedtype ReactiveBase 

    # rx 是  Reactive 类型,并将 ReactiveBase 传入
    static var rx: Reactive<ReactiveBase>.Type { get set }

    var rx: Reactive<ReactiveBase> { get set }
}

 

Reactive 中 还对 ReactiveCompatible进行了 协议的拓展,在这个扩展中,通过调用rx,返回的是

Reactive 类型 或者Reactive实例

extension ReactiveCompatible {
    # Reactive 类型
    public static var rx: Reactive<Self>.Type {
        get {  return Reactive<Self>.self }
    }
    # Reactive 实例
    public var rx: Reactive<Self> {
        get {  return Reactive(self) }
    }
}

 

在看一下 Reactive 的 实现,是一个 包含参数泛型 Base 的结构体

public struct Reactive<Base> {
    public let base: Base
    # 将 Reactive 的初始化调用者 设置为 base
    public init(_ base: Base) {
        self.base = base
    }
}

 

如上文中 点击按钮的 tap,即 button.rx.tap, 类型就是 UIButton 类型,将 UIButton 的实例 设置为 base

那么想 实现 万物皆rx,只需要简单的一步

extension NSObject: ReactiveCompatible { }

这样就可以让所有继承于 NSObjce 的对象,都遵循 ReactiveCompatible 协议,即 万物皆rx

 

Observable

Observable 意味着,可被观察的,也就是可观察序列,什么是序列呢?

我理解的就是 具备 发出事件能力的 的一种信号


比如:

肚子饿了 -> 吃饭

肚子饿了 可以作为一个 可观察序列,当我们大脑感知到 肚子饿了,就可以执行 去吃饭的操作

 

TextField 输入 -> 显示

TextField 输入操作可以作为一个序列,可以监听到 输入的内容

 

接下来

就开始调试 mojito 了

看一个订阅过程:

# 创建
let observable = Observable<String>.create { (observe) -> Disposable in
    # 发送
    observe.onNext("mojito")
    return Disposables.create()
}
# 订阅
observable.subscribe(onNext: { text in
    print(text)
}).disposed(by: rx.disposeBag)

// print "mojito"
复制代码



调试开始

Observable 可观察序列

  • step1
# Observable 继承于  ObservableType
public class Observable<Element> : ObservableType {
    # 资源的引用计数 +1
    init() {
        _ = Resources.incrementTotal()
    }
     # 提供被订阅的能力,由子类实现
    public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
        rxAbstractMethod()
    }
     # 将 Observable 类转为 Observable 实例
    public func asObservable() -> Observable<Element> {
        return self
    }
     # 资源的引用计数 -1
    deinit {
        _ = Resources.decrementTotal()
    }
}

 

可是这里并没有看到序列的创建,但是可以看到一个 继承关系: Observable<Element> : ObservableType

进入 ObservableType

  • step2
# 协议  ObservableType,继承于 ObservableConvertibleType
public protocol ObservableType: ObservableConvertibleType {
    func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element
}

# ObservableType 扩展
extension ObservableType {
    # 提供了一个方法,将遵守 ObservableType 协议的对象 转为 Observable 实体
    public func asObservable() -> Observable<Element> {
        return Observable.create { o in
            return self.subscribe(o)
        }
    }
}

这里还是 没有看到 订阅的方法

还发现了 自己的爸爸是个协议, 还有爷爷 ObservableConvertibleType

 

持着怀疑的态度,你又点进了 ObservableConvertibleType

  • step3
# 也是个协议
public protocol ObservableConvertibleType {

    associatedtype Element
    typealias E = Element
    
    # 定义了一个方法,返回类型 Observable 可观察序列
    func asObservable() -> Observable<Element>
}

 

 

 

 

可恶

既然这条路走不通,只能先不走了

哪里跌倒

我就躺在哪里

为了达到万物皆序列,我们就要想办法把所有事件转化为序列,asObservable() 即为 RxSwift 的精髓

 

Observable.create()

点击 creat ,豁然开朗,原来创建是通过 ObservableType 扩展,这也同时证明了 OOP 的好处,可扩展性强

ObservableType 像是一家名叫 ObservableType 的连锁公司

它可以在任何地方开个分店

实现自己公司的业务

  • step4
#  ObservableType 的扩展
extension ObservableType {
    public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element> {
        # 返回一个 匿名观察序列,将 subscribe 逃逸闭包传入
        return AnonymousObservable(subscribe)
    }
}

点击 AnonymousObservable 进入

  • step5
# 私有方法,外界无法共享
# AnonymousObservable 继承于  Producer
final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable
    # 定义 闭包属性
    let _subscribeHandler: SubscribeHandler
    # 将外界传入的 闭包 保存
    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
    }
    # 重写 父类 Producer 提供的 run 方法
    override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
        # 初始化匿名管道,传入一个订阅者
        let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
        let subscription = sink.run(self)
        return (sink: sink, subscription: subscription)
    }
}

 

这里又来了个 Producer,点击 Producer

  • step6
# Producer 同样继承于 Observable
class Producer<Element> : Observable<Element> {
    override init() {
        super.init()
    }

# 这里涉及到了线程,如果  CurrentThreadScheduler 指定了某个线程,那么就会在指定线程中 执行 run
# 否则 就会在当前线程中 执行 run
# SinkDisposer实例 disposer,用来管理资源释放
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
         if !CurrentThreadScheduler.isScheduleRequired {
            // The returned disposable needs to release all references once it was disposed.
            let disposer = SinkDisposer()
            let sinkAndSubscription = self.run(observer, cancel: disposer)
            disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
            return disposer
        }
        else {
            return CurrentThreadScheduler.instance.schedule(()) { _ in
                let disposer = SinkDisposer()
                let sinkAndSubscription = self.run(observer, cancel: disposer)
                disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
                return disposer
            }
        }
  }
# 抽象方法,子类去实现,也就是匿名序列 AnonymousObservable
func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
    rxAbstractMethod()
    }
}

相信到此,你我都已经微醺了

你问我什么是 序列 ?

我 指 着 大 海 的 方 向

 

目前也只能先画个图,继续观望

 

 

 

 

小结

  • 小结

    • 我们调用父类协议的 creat 方法 ,生成 匿名观察序列,即Producer 的子类AnonymousObservable
    • AnonymousObservable 保存外界传入的 闭包
    • 负责资源管理,引用计数的 是 Observable 抽象类,不实现方法
    • Producer 类 实现 外界 subscribe 方法,并安排线程调度
    • 具体的 run,由 AnonymousObservable 实现,父类 Producer不负责

 

ok ,继续往下走

subscribe(onNext:) 订阅

点击 subscribe 进入,可以看到 ObservableType 的扩展,提供了 subscribe.on 和 subscribe.onNext 2个方法

此处省略了 subscribe.on

  • step7
extension ObservableType {
    ...
    
    public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
        -> Disposable {
            ....
            # 创建一个 匿名订阅者  AnonymousObserver
            # 对外界传入的执行闭包 进行保存
            let observer = AnonymousObserver<Element> { event in
                switch event {
                case .next(let value):
                    onNext?(value)
                case .error(let error):
                    if let onError = onError {
                        onError(error)
                    } else { Hooks.defaultErrorHandler(callStack, error) }
                    disposable.dispose()
                case .completed:
                    onCompleted?()
                    disposable.dispose()
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}

这里将 外界需要执行的 闭包,即本例中的 print(text),生成 AnonymousObserver 实例,传入

self.asObservable().subscribe(observer)

也就是说,这个 AnonymousObserver实例,会通过 Producer 调用 subscribe

然后由 子类 AnonymousObservable,序列实例去调用 run方法

 

来到文中,step 5 的 run 方法,如下

# 将外界 需要执行的闭包 ,以及 资源销毁实例 生成的 元祖 传入  AnonymousObservableSink
# 生成 sink 管道实例,并执行 run 
# 将run 之后生成的实例,赋值给  subscription,并返回 subscription 和  sink

override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
    let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
    let subscription = sink.run(self)
    return (sink: sink, subscription: subscription)
}

 

进入 AnonymousObservableSink

  • step8
final private class AnonymousObservableSink<Observer: ObserverType>: Sink<Observer>, ObserverType {
    typealias Element = Observer.Element 
    typealias Parent = AnonymousObservable<Element>
    
    # 调用父类 Sink 的初始化方法,传入  observer 和 cancel,即 管道 AnonymousObservableSink 持有 这2个属性
    override init(observer: Observer, cancel: Cancelable) {
        super.init(observer: observer, cancel: cancel)
    }

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 1 {
                return
            }
            self.forwardOn(event)
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.forwardOn(event)
                self.dispose()
            }
        }
    }
    ### 熟悉的东西有没有
    # 这里看到了  _subscribeHandler,也就是 发出的信号,保存的闭包
    
    func run(_ parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self))
    }
}

到这里,我们就会发现 sink 管道 它很重要

它持有了

要销毁的实例,发出序列的闭包,执行序列的闭包

 

 

 

这里的  AnyObserver(self) 是为了 兼容传入 闭包的类型, 本文对应的 是 String


也就是说,一旦外界开始订阅序列

那么 火车序列 就开始发动了,但是 怎么响应? 下一步往哪开?

这就要看 AnyObserver(self),做了什么,进入 AnyObserver, 查看init

 

 public init<Observer: ObserverType>(_ observer: Observer) where Observer.Element == Element {
    self.observer = observer.on
}

你会发现这里的 self.observer 保存了 自己的 on 方法

也就是保存的了一个 function

即 会调用 step8 中 的 on, 然后 去调用 父类Sink 的 forwardOn

 

  • step9
# 父类 Sink
class Sink<Observer: ObserverType> : Disposable {
    final func forwardOn(_ event: Event<Observer.Element>) {
        #if DEBUG
            self._synchronizationTracker.register(synchronizationErrorMessage: .default)
            defer { self._synchronizationTracker.unregister() }
        #endif
        if isFlagSet(self._disposed, 1) {
            return
        }
        # 订阅者
        self._observer.on(event)
    }
}

 

在父类 forwardOn中, 由订阅者执行 on 事件

可是 订阅者 AnonymousObserver 类有没有 on 方法,只有 onCore

所以去 AnonymousObserver 的 父类中 ObserverBase 寻找

class ObserverBase<Element> : Disposable, ObserverType {
    private let _isStopped = AtomicInt(0)

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 0 {
                self.onCore(event)
            }
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.onCore(event)
            }
        }
    }
    # 子类实现
    func onCore(_ event: Event<Element>) {
        rxAbstractMethod()
    }
}

最后 AnonymousObserver 调用自己的 onCore 执行 eventHandler 闭包

到此

整个执行的过程算是走完了

关于资源回收的内容,后续文章会写到


到此

mojito 初体验 结束

 

 

 

小结

  • 小结
    • 通过 AnonymousObservable 保存 可观察序列
    • 通过 AnonymousObserve 保存 执行闭包
    • 外界开始订阅,由 Producer 调度线程,执行 subscribe
    • 生成 SinkDisposer 以及 observer 实例 元祖
    • 将 元祖 注入 Sink 管道
    • Sink 处理事件,发出信号,响应序列
    • 资源回收

 

简单的流程图如下

 

 

 

而我的写法,轻松像魔法

有了RxSwift ,日常开发就变得酣畅淋漓了,比如

  • 监听 tableView 的滚动:
 tableView.rx.contentOffset.subscribe(onNext: { contentOffset in
    /// 修改透明度
 })
.disposed(by: rx.disposeBag)

 

  • 监听textField 输入
 textField.rx.text.skip(1).subscribe(onNext: { (text) in
    print("输入的是 : \(text!)")
 })
 .disposed(by: rx.disposeBag)

 

  • 按钮点击
 self.messageBtn.rx.tap.subscribe(onNext: { in
    Navigator.push("")
 })
 .disposed(by: rx.disposeBag)

 

  • tableView 绑定数据源 代理
  # 这里需要导入 RxDataSources
  dataSource = RxTableViewSectionedReloadDataSource(configureCell: { (_, tab, indexPath, item) -> UITableViewCell in
    let cell = tab.dequeue(Reusable.settingCell, for: indexPath)
    cell.bind(to: item)
    return cell
  })
  
  # 或者
  let items = Observable.just([
    "Just",
    "Relay",
    "From",
    "Driver",
    "merge"
  ])
  
 items.bind(to: tableView.rx.items) { (tableView,_,element) in
    let cell = self.tableView.dequeue(TestV.normalCell)
    cell?.textLabel?.text = element
    return cell!
  }
  .disposed(by: rx.disposeBag)

 

  • tableView 点击代理
 tableView.rx.itemSelected.subscribe(onNext: { indexPath in
   /// doSomething
 })
 .disposed(by: rx.disposeBag)

 

  • 配合 HandyJSON 转model
extension Response {
    func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> T {
        let jsonString = String.init(data: data, encoding: .utf8)
        if let modelT = JSONDeserializer<T>.deserializeFrom(json: jsonString) {
            return modelT
        }
        return JSONDeserializer<T>.deserializeFrom(json: "{\"msg\":\"解析有误\"}")!
    }
}

extension ObservableType where Element == Response {
    /// 注释
    public func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> {
        return flatMap { response -> Observable<T> in
            return Observable.just(response.mapHandyJsonModel(T.self))
        }
    }
}

# 配合 Moya 
static func getTopList() -> Observable<HomeResponseModel> {
    return HomeApiProvider.rx.request(.Top).asObservable().mapHandyJsonModel(HomeResponseModel.self)
}

 

  • 多个请求合并
 Observable.zip(HomeApi.getTopList(), HomeApi.getRecommondList()).subscribe(onNext: { topResponse, recommodResponse in
    /// 数据处理
  }).disposed(by: self.rx.disposeBag)


等等....

先介绍一点简单的用法

后续会慢慢更新

 

 

 

 

这世界因我让你不再受折磨

RxSwift 熟悉了之后,会让我们的代码变得 简洁且优雅

它面向协议编程,我们面向业务编程

RxSwift 需要慢慢品味

听一遍 mojito 肯定是不够的

不说了

听歌去了~


对了

没喝过 mojito 的 就从这里开始吧~



如何获取?
转发这篇文章,关注我,私信回复“资料”即可获取高清大纲,以上 spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构
如何私信?
关注我后,在手机,点进头像进我的主页,主页上方右上角有个私信,点击私信,如何回复关键字“资料”即可

 

Flutter 完整学习文档 - 从入门到精通 Widget 就像乐高积木,Flutter 中所有的东西都是 Widget。一个按钮是 Widget,一段文字是 Widget,甚至布局、边距、对齐方式也是 Widget!"万物皆 Widget" 阅读详情

相关推荐

论文阅读——Bayesian Knowledge Fusion(贝叶斯知识融合)

该篇论文解决了不确定环境中的信息融合问题。想象一下,有多位专家针对同一情况构建概率模型,我们希望汇总他们提供的信息。直接合并每个信息可能会遇到几个问题。例如,专家们可能不同意某个事件发生的概率,或者他们可能不同意两个事件之间因果关系的方向(例如,一个人认为 A 导致 B,而另一个人认为 B 导致 A)。他们甚至可能不同意概率网络中一组变量之间的整个依赖结构。

qq_64164071的博客 1497

RxSwift+Moya+ObjectMapper优雅的网络请求

优雅的网络请求本人已写了一个开源的拿来及用的[Swift项目框架](https://github.com/liuniuliuniu/LLProgramFramework.Swift) 可以参考此框架来通篇阅读此文章更有帮助  有喜欢的还望送人玫瑰手留余香哦 当然这个拿来及用的[Swift项目框架](https://github.com/liuniuliuniu/LLProgramFramewor...

星宇大前端 1823

新手必看:CiscoPacket Tracer从零搭建局域网(含ARP协议详解)

本文为网络新手提供了一份使用Cisco Packet Tracer从零搭建局域网的详细指南。通过构建基础网络拓扑、配置IP地址,并深入剖析ARP协议的工作原理,帮助读者理解IP地址与MAC地址的映射关系,掌握局域网通信的核心机制。

weixin_29275257的博客 205

swift 同步 网络请求_RxSwift: 网络请求,数据共享分发

一般 OOP 常见的一步,网络请求,获取数据,刷新 UI使用 RxSwift, 这一步,可拆分成两步,网络请求,获取数据,是一步刷新 UI,是第二步多个控制器,有同样的网络请求,去做数据共享与同步的场景下,有用采用通知:去做一个网络请求,刷新界面。这样的指令会有两条NotificationCenter.default.rx.notification(.readNetRequest).takeUnt...

weixin_39735247的博客 247

父子Agent架构:解决AI系统上下文污染的技术方案

在AI系统设计中,上下文管理是核心挑战之一。传统单Agent架构在处理复杂任务时,常面临上下文无限膨胀导致的信息淹没和性能下降问题。父子Agent架构通过职责分离和上下文隔离机制,采用分而治之的思想,将大任务拆解为多个子任务由专门子Agent处理。该架构中父Agent负责任务规划和结果汇总,子Agent执行具体任务后立即销毁中间状态,通过精炼摘要进行通信。这种设计不仅能有效控制上下文长度,还能提升系统稳定性和执行效率,特别适用于编程辅助、自动化测试等需要多步骤处理的场景。父子Agent架构体现了计算机科学中

weixin_42531710的博客 353

对雷达中相位补偿概念的一些理解

基于多普勒相位补偿的速度扩展方法和DBF测角,两者本质上都是对相位进行补偿。

qq_42235129的博客 4031

RxDataSources与TableView中实现界面展示(二)

通过按钮刷新界面参数,设置延时为2s // ViewController.swift // RxSwiftTest // // Created by travey on 2018/11/5. // Copyright © 2018年 ZhouShijie. All rights reserved. import UIKit import RxSwift import RxCoco...

小龙虾 1638

STM32步进电机控制三大方案:GPIO/定时器/PWM深度对比

步进电机控制是嵌入式运动控制的基础技术,其核心在于精确生成脉冲(PUL)、方向(DIR)和使能(EN)三路数字信号。原理上,脉冲频率决定转速,脉冲数量决定位置,方向电平决定转向,而使能时序保障驱动器可靠启停。该技术具有高定位精度、开环稳定性与低成本优势,广泛应用于3D打印机、CNC设备、自动化产线等场景。在STM32平台实现时,需兼顾硬件隔离设计(如6N137光耦)、HAL库抽象封装及实时性约束。本文围绕GPIO模拟、定时器中断与PWM比较输出三种主流方法,系统剖析其时序机制、CPU开销、抗干扰能力与工业适

weixin_35755640的博客 88

RxSwift实现TableView数据绑定三部曲

var dataList = BehaviorSubject(value: [SectionModel<String,Any>]()) //1.tableView创建数据源 let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String,Any>>(configureCell:{ _, tableView,indexPath,element in ...

weixin_46336883的博客 3012

使用linuxdeployqt打包Qt程序问题及解决方法

安装过程中提示缺少依赖multiarch-support: 下载对应依赖包。安装过程中提示缺少libpq.so.5: 下载对应依赖包。下载libmysqlclient18/5.6.25。

weixin_74239923的博客 1059

手把手教你学SOME/IP「1.0•概述」

本文介绍了SOME/IP协议的基本概念和主要特点。SOME/IP全称为"Scalable service-Oriented MiddlewarE over IP",是一种面向服务的车载嵌入式通信协议,支持远程过程调用、事件通知等功能。文章指出SOME/IP是AUTOSAR标准的一部分,在车载以太网架构中处于应用层位置,负责服务调度和通信封装。协议具有可扩展性强、资源消耗低、兼容性好等优势,能满足汽车电子领域对实时性、可靠性的严格要求。同时,文章也说明了SOME/IP的正确书写规范,并解释

nihaoljq2010的博客 679

RxSwift系列(二)操作符

buffer方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。

KWMax 1381

SAP在sap我定义了三个帐套 T9 SGD,I9 CNY, C9 CMY 想使用三个不同的币种,那么 我在定义和激活非主分类账时 如何定义各自的币种 ?

摘要:在SAP中为非主分类账(T9、I9、C9)配置不同币种(SGD、CNY、MYR),需通过三个步骤实现:1)在FINSC_LEDGER中定义分类账货币类型;2)在OB22中为公司代码0919配置平行货币;3)在"定义和激活非主分类账"中关联币种。关键注意事项包括维护自定义货币类型(以Y/Z开头)、设置OB08汇率以及独立汇率评估。完成后可通过FB50测试凭证和FAGLL03验证各账套的币种金额显示。

金牌架构师 1012

RxSwift之RxDataSources使用,UITableView 和 UICollectionView 数据源

单组数据绑定 let data = Observable<[String]>.just(["first element", "second element", "third element"]) data.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell in cell.text...

代码是贝多芬的音符 1965

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

RxDataSources与TableView实现界面展示(一)

// ViewController.swift // RxSwiftTest // // Created by travey on 2018/11/5. // Copyright © 2018年 ZhouShijie. All rights reserved. import UIKit import RxSwift import RxCocoa import SnapKit imp...

小龙虾 2244

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

RxDataSources 项目常见问题解决方案

RxDataSources 是一个为 RxSwift 设计的开源项目,主要用于简化 UITableView 和 UICollectionView 的数据源管理。它通过提供高效的数据绑定机制,帮助开发者减少编写繁琐的 delegate 方法,从而提高开发效率。该项目的主要编程语言是 Swift。 ## 新手使用项目时需要注意的3个问题及解决步骤 ### 问题1:如何正确绑定数据到 UITable...

gitblog_01074的博客 657

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

学习 RxSwift操作符

ViewModel 的核心功能是把 Model 数据转换为用于 UI 呈现所需的数据。其实RxSwift 的操作符就是负责转换的,使用合适的操作符能帮我们减少代码量并提高生产力。 一、过滤操作符 001 filter 操作符用于过滤不需要的事件 func filterFunc() { Observable.of(2,23,5,45,1,21).filter{ $0 > 20 }.subscribe(onNext:{

Coding_Physical的专栏 541

RxSwift | 万物皆 rx 的原因

万物皆 rx

无夜之星辰的博客 659

RxSwift学习心得

最近接触了RxSwift,有一些心得自己学习体会,有不对的地方还望各路大神多多指教,不喜勿喷,没有官方文档那么正式,根据自己的理解来的RxSwift ObserVerable 获得Observable combineLatest 简单使用 binTO 简单使用 用RxSwift和Alamofire去请求数据 END RxSwiftRxSwift的目的是让让数据/事件流和异步任务能够更方便的序列化处理

一位iOS同学的博客 2214

RxSwift中的 Disposed by bag的含义

Dispose bags 类似于RX中的ARC的行为。当DisposeBag被释放时,它将在每个添加的一次性用品上调用dispose并释放内存。 它用于处理在闭包中传递的旧引用和不再需要的资源(显然不使用它们):例如,一个HTTP连接,数据库连接或缓存。 Dispose bags are used to return ARC like behavior to RX. When a DisposeB...

陈云峰技术博客 2514

RxSwift中垃圾袋回收袋DisposeBag的使用技巧和demo下载

目录垃圾袋移除通知订阅关系赋值新的垃圾袋会让之前垃圾袋绑定的订阅关系释放用来给timer停止demo下载地址 前言:前端时间学习了一下RxSwift框架,全学完以后再回过头来发现,后来理解的垃圾袋和最开始时候不一样,今天稍微总结一下 垃圾袋移除通知订阅关系 let disposeBag = DisposeBag() //成员变量 override func viewDidLoad() { super.viewDidLoad() let UserNoti1 = "UserNoti1"

小手琴师的博客 1668

RxSwift之UI控件UITextField与UITextView扩展的使用

一、监听单个 textField 内容的变化(textView 同理) 将 textField 里输入的内容实时地显示到控制台中,示例代码: // 创建文本输入框 let textField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30)) textField.borderStyle = UITextField.BorderStyle.roundedRect self.view.addSubview(textField) /

╰つ栺尖篴夢ゞ 3109

基于Moya、RxSwift和ObjectMapper优雅实现REST API请求

在Android开发中有非常强大的 Retrofit 请求,结合RxJava可以非常方便实现 RESTful API 网络请求。在 iOS开发中也有非常强大的网络请求库 Moya ,Moya是一个基于 Alamofire 开发的,轻量级的Swift网络层。Moya的可扩展性非常强,可以方便和RXSwift、ObjectMapper结合。 测试 REST API 定义 我们先用服务端定义几个REST...

378

对Observable.of方法的探究

public static func of(_ elements: E ..., scheduler: ImmediateSchedulerType = CurrentThreadScheduler.instance) -> Observable<E> { return ObservableSequence(elements: elements, schedul...

enghou123的博客 1057

RxSwift笔记 - RxCocoa 基础 (四) : UITableView + RxDataSources

文章目录RxDataSources 介绍单分区 TableView方式一:使用自带的Section方式二:使用自定义的Section多分区的 TableView方式一:使用自带的Section方式二:使用自定义的Section RxDataSources 介绍 RxDataSources Github 地址: RxDataSources 官方介绍: UITableView and UIColle...

Mazy's Blog 3318

RxSwift笔记 - RxCocoa 基础 (一)

UILabel UITextField UITextView UIButton UISlider UIStepper UISwitch UISegmentedControl UILabel 文字绑定到 UILabel let label = UILabel() // ... /// 值绑定 Observable.just("Hello RxSwift") ...

Mazy's Blog 3123
上一篇: Eclipse的Debug介绍与技巧
下一篇: 4000字长文介绍Java日志中框架,最全面
java架构那些事
博客等级 码龄6年 6粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值