美文网首页rxswiftiOS Dev
RxSwift 项目实战举例

RxSwift 项目实战举例

作者: AKyS佐毅 | 来源:发表于2017-08-06 12:34 被阅读555次
    RxSwift.png

    本文非基础文章,主要举例实际开发中可能会遇到的场景。

    如何实现多按钮互斥单选操作

        //MARK: - 单选操作
        func rxRedio(){
            // force unwrap to avoid having to deal with optionals later on
            let buttons = [self.button1, self.button2, self.button3].map { $0! }
            
            // create an observable that will emit the last tapped button (which is
            // the one we want selected)
            let selectedButton = Observable.from(
                buttons.map { button in
                    button.rx.tap.map { button }
                }
                ).merge()
            
            // for each button, create a subscription that will set its `isSelected`
            // state on or off if it is the one emmited by selectedButton
            buttons.reduce(Disposables.create()) { disposable, button in
                let subscription = selectedButton.map { $0 == button }
                    .bind(to: button.rx.isSelected)
                
                // combine two disposable together so that we can simply call
                // .dispose() and the result of reduce if we want to stop all
                // subscriptions
                return Disposables.create(disposable, subscription)
                }
                .addDisposableTo(bag)
        }
    

    如何实现数据的过滤操作

        
        func filterArray (){
            var allCites: Variable<[CiteModel?]> = Variable([])
            var searchQuery: Variable<String> = Variable("")
            
            let model1 = CiteModel()
            model1.cite = "131"
            
            let model2 = CiteModel()
            model2.cite = "331"
            
            let model3 = CiteModel()
            model3.cite = "121"
            
            let model4 = CiteModel()
            model4.cite = "1224"
            
            allCites.value = [model1, model2, model3]
            
            
            //通过combineLatest我们可以很容易实现两者任意一个改变都去改变输出结果的效果
            var shownCites: Observable<[CiteModel?]> = Observable.combineLatest(allCites.asObservable(), searchQuery.asObservable()) { allCites, query in
                allCites.filter { ($0?.cite.contains(query))! }
            }
            
            func filterCitesByQuery(query: String) {
                searchQuery.value = query
            }
            
            
            filterCitesByQuery(query: "2")
            
            shownCites.subscribe {  (event: Event<[CiteModel?]>) in
                //guard: 用来处理提前返回,给event重新赋值,如果event =nil,直接return。优点是防止代码嵌套过多
                guard event.element != nil else { return }
                
                for element in event.element! {
                    print(element?.cite ?? "")
                }
                }.addDisposableTo(bag)
            
            
            allCites.value = [model1, model2, model3,model4]
            
            //通过Observable.from 将每一个元素都传递出来
            allCites.asObservable()
                .flatMap { CiteModel in
                    Observable.from(CiteModel) // <- magic here
                }
                .subscribe(onNext: { item in
                    print(item?.cite ?? "")
                })
                .addDisposableTo(bag)
        }
    

    如何合并两个通知

        func rxNotification(){
            
            self.pushButton.rx.tap.subscribe {  (event: Event<()>) in
                NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "121"), object: nil)
                }.addDisposableTo(bag)
            
            let a = NotificationCenter.default.rx.notification(NSNotification.Name.UIApplicationWillEnterForeground)
            let b = NotificationCenter.default.rx.notification(Notification.Name(rawValue: "121"))
            
            Observable.of(a, b)
                .merge()
                .takeUntil(self.rx.deallocated)
                .subscribe{ _ in
                    print("如何合并两个通知")
                }.addDisposableTo(bag)
        }
    

    如何监听某个方法执行 sentMessage 和 methodInvoked 只有一个区别,sentMessage 会在调用方法前发送值, methodInvoked 会在调用方法后发送值

         //方法一
         self.rx.sentMessage(#selector(UIViewController.viewWillAppear(_:)))
                .subscribe({ e in
                    print(e)
                })
                .addDisposableTo(disposeBag)
    
    
         rx.methodInvoked(#selector(ViewController.viewWillAppear(_:)))
                .subscribe(onNext: { value in
                   print("3")
               })
               .addDisposableTo(disposeBag)
    
    

    另外,如果我们需要在一个控制中,监听另一个控制器是否执行了某个方法,那么该怎么处理呢?

    import UIKit
    
    class ListViewController: UIViewController {
    
        override  dynamic func viewDidLoad() {
            super.viewDidLoad()
             //do somethings 
        }
    
        override dynamic func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
           // do somethings 
        }
        
        dynamic func hello() {
            // do somethings 
        }
    }
    
    
        let list = ListViewController()
            
        list.rx.sentMessage(#selector(ListViewController.hello)).subscribe(onNext: {
                print($0)
         }).addDisposableTo(bag)
            
        list.rx.sentMessage(#selector(ListViewController.viewDidAppear(_:))).subscribe(onNext: {
                print($0)
         }).addDisposableTo(bag)
            
        list.viewDidAppear(true)
        list.hello()
    
    

    实际上,NSObject.rx.sentMessage和NSObject.rx.methodInvoked是基于方法swizzling,基于Swift方法调用的v表,它不受方法swizzling的影响。
    如果要在swift中使用objc_msgSend方法,可以在函数上使用动态修饰符。
    但在我看来,使用NSObject.rx.sentMessage和NSObject.rx.methodInvoked不是很好。

    如何在长链(像a,b,c,d,e,...)中做一些Observable

            let a = PublishSubject<Int>()
            let b = PublishSubject<Int>()
            let c = PublishSubject<Int>()
            
            a.bind(to: b).addDisposableTo(bag)
            b.bind(to: c).addDisposableTo(bag)
            
            c.subscribe(onNext: {
                print($0) // called
            }).addDisposableTo(bag)
            
            
            let d = a.do(onNext: {
                print($0)
            })
            Observable.of(b, c, d).merge().subscribe(onNext: {
                print($0) // called
            }).addDisposableTo(bag)
    
            a.onNext(1)
            a.onNext(2)
    
    

    UserDefaults KVO API 重复执行问题 Apple's Bug

    import UIKit
    import RxCocoa
    import RxSwift
    import RxDataSources
    
    
    extension Reactive where Base: UITableView {
        
        var didHighlightRowAt: ControlEvent<IndexPath> {
            let selector = #selector(UITableViewDelegate.tableView(_:didHighlightRowAt:))
            let events = delegate
                .methodInvoked(selector)
                .filter({ ($0.last as? IndexPath) != nil })
                .map({ $0.last as! IndexPath })
            return ControlEvent(events: events)
        }
    }
    
    
    class RxTableViewController: UIViewController {
    
        @IBOutlet weak var tableView: UITableView!{
            didSet {
                tableView.register(UITableViewCell.self, forCellReuseIdentifier: String(describing: UITableViewCell.self))
                
                tableView.rx
                    .itemSelected
                    .subscribe { (indexPath) in
                        UserDefaults.standard.set("\(indexPath)", forKey: "key")
                       
                        self.navigationController?.pushViewController(RxSwiftLoginController(), animated: true)
                        
                    }
                    .disposed(by: disposeBag)
            }
        }
        
        let disposeBag = DisposeBag()
    
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.rx.sentMessage(#selector(UIViewController.viewWillAppear(_:)))
                .subscribe({ e in
                    print(e)
                })
                .addDisposableTo(disposeBag)
            
            
            UserDefaults.standard.rx
                .observe(String.self, "key")
                .debounce(0.1, scheduler: MainScheduler.asyncInstance) //iOS bug, v10.2  必须要加这句话
                .subscribe(onNext: { (value) in
                    if let value = value {
                        print(value)
                    }
                })
                .disposed(by: disposeBag)
            
            let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, String>>()
            
            dataSource.configureCell = { (dataSource, tableView, indexPath, item) in
                let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UITableViewCell.self), for: indexPath)
                cell.textLabel?.text = item
                
                return cell
            }
            
            Observable.just([SectionModel(model: "", items: (0..<5).map({ "\($0)" }))])
                .bind(to: tableView.rx.items(dataSource: dataSource))
                .disposed(by: disposeBag)
            
            
            let observable = UITableView().rx.didHighlightRowAt.asObservable()
            observable.subscribe{ (indexPath) in
                
            }.disposed(by: disposeBag)
            
            //通过设置dataSource.sections达到刷新tableView 的目的
            dataSource.setSections([SectionModel(model: "", items: (0..<10).map({ "\($0)" }))])
    
    
        }
    }
    
    

    如何防止多次点击事件,添加loading视图重复的问题

    getClicksEvents()
    .flatMapFirst(aVoid -> getRequestObservable())
    .retry()
    .subscribe( result -> //do your thing );
    
    

    如何处理检查一些UIButton的isSelected状态,以提供另一个按钮的isEnabled状态。后一个按钮只有当其他其他按钮之一被选择为true时启用。

    let state: Observable<Bool>
    
    state.bindTo(button.rx.isSelected)
        .disposed(by: disposeBag)
    
    state.bindTo(button1.rx.isEnabled)
        .disposed(by: disposeBag)
    

    如何通过在RxSwift中组合它们来处理多个按钮的动作?

    let tag1 = button1.rx.tap.map { [unowned self]  _ in return self.button1.tag}
    let tag2 = button2.rx.tap.map { [unowned self]  _ in return self.button2.tag}
    let tags = Observable.of(tag1, tag2).merge()
    

    如何移除一个通知

      NotificationCenter.default.rx.notification(Notification.Name(rawValue: "121")).subscribe { _ in
            
       }.addDisposableTo(bag)
    

    如何修复bindTo多次导致由tableviewcell重用?

    import UIKit
    import RxCocoa
    import RxSwift
    
    private var prepareForReuseBag: Int8 = 0
    
    @objc public protocol Reusable : class {
        func prepareForReuse()
    }
    
    extension UITableViewCell: Reusable {}
    extension UITableViewHeaderFooterView: Reusable {}
    extension UICollectionReusableView: Reusable {}
    
    extension Reactive where Base: Reusable {
        var prepareForReuse: Observable<Void> {
            return Observable.of(sentMessage(#selector(Base.prepareForReuse)).map { _ in }, deallocated).merge()
        }
        
        var reuseBag: DisposeBag {
            MainScheduler.ensureExecutingOnScheduler()
            
            if let bag = objc_getAssociatedObject(base, &prepareForReuseBag) as? DisposeBag {
                return bag
            }
            
            let bag = DisposeBag()
            objc_setAssociatedObject(base, &prepareForReuseBag, bag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            
            _ = sentMessage(#selector(Base.prepareForReuse))
                .subscribe(onNext: { [weak base] _ in
                    let newBag = DisposeBag()
                    objc_setAssociatedObject(base, &prepareForReuseBag, newBag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
                })
            
            return bag
        }
    }
    

    或者

    class TableViewCell: UITableViewCell {
    
       private(set) var disposeBag = DisposeBag()
    
       override func prepareForReuse() {
          super.prepareForReuse()
          disposeBag = DisposeBag() // because life cicle of every cell ends on prepare for reuse
       }
    }
    
    
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DiaryItemCell
    
    cell.commentButton.rx_tap
                .subscribeNext{
                    showAlert("Hi")
                }.addDisposableTo(cell.disposeBag)
    
            return cell
    

    如何实现筛选操作

    
        var shownCities = [String]() // Data source for UITableView
        let allCities = ["New York", "London", "Oslo", "Warsaw", "Berlin", "Praga"] // Our mocked API data source
        let disposeBag = DisposeBag() // Bag of disposables to release them when view is being deallocated
    
         searchBar
                .rx.text // Observable property thanks to RxCocoa
                .orEmpty // Make it non-optional
                .debounce(0.5, scheduler: MainScheduler.instance) // Wait 0.5 for changes.
                .distinctUntilChanged() // If they didn't occur, check if the new value is the same as old.
                .filter { !$0.isEmpty } // If the new value is really new, filter for non-empty query.
                .subscribe(onNext: { [unowned self] query in // Here we subscribe to every new value, that is not empty (thanks to filter above).
                    self.shownCities = self.allCities.filter { $0.hasPrefix(query) } // We now do our "API Request" to find cities.
                })
                .addDisposableTo(disposeBag) // Don't forget to add this to disposeBag. We want to dispose it on deinit.
    

    相关文章

      网友评论

      • 王博达:你好我想问一下 如何修复bindTo多次导致由tableviewcell重用 这段代码里面的
        sentMessage(#selector(Base.prepareForReuse))
        是怎么确定 prepareForReuse 方法是自己在 Reactive 的 extension 里写的方法而不是 cell 自带的?
        因为 base 指的是 cell 而不是 reactive

      本文标题:RxSwift 项目实战举例

      本文链接:https://www.haomeiwen.com/subject/rmeglxtx.html