RxSwift: Sử dụng Delegate Pattern trong RxSwift với DelegateProxy

I.Giới thiệu: Delegate Pattern trong iOS là một pattern thông dụng và phổ biến, được áp dụng nhiều trong framework UIKit của Apple. Delegate Pattern giúp cho lập trình viên có thể giải quyết được nhiều bài toán trong quá trình phát triển phần mềm, tuy nhiên thì việc implement pattern này đôi lúc lại

I.Giới thiệu:

Delegate Pattern trong iOS là một pattern thông dụng và phổ biến, được áp dụng nhiều trong framework UIKit của Apple. Delegate Pattern giúp cho lập trình viên có thể giải quyết được nhiều bài toán trong quá trình phát triển phần mềm, tuy nhiên thì việc implement pattern này đôi lúc lại cồng kềnh và làm cho code thiếu đi sự tinh gọn. Để giải quyết vấn đề trên chúng ta có thể sử dụng Delegate Pattern kết hợp với RxSwift để việc implement trở nên gọn nhẹ và dễ dàng tái sử dụng hơn. Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách chuyển một delegate sang thành một observable, cụ thể là thông qua ví dụ với WKNavigationDelegate của WKWebView.

II. Tạo DelegateProxy class:

DelegateProxy đóng vai trò là một cầu nối (hay còn gọi là adapter) để chuyển đổi qua lại giữa delegateobservable. Trong DelegateProxy sẽ có hai phương thức currentDelegatesetCurrentDelegate thực hiện vai trò getsetdelegate cho WKWebView.

importFoundationimportRxSwiftimportRxCocoaimportWebKitclassWKNavigationDelegateProxy:DelegateProxy<WKWebView,WKNavigationDelegate>,WKNavigationDelegate,DelegateProxyType{/// Typed parent object.weakprivate(set)var webView:WKWebView?/// - parameter webView: Parent object for delegate proxy.init(webView:ParentObject){self.webView = webView
        super.init(parentObject: webView, delegateProxy:RxWKNavigationDelegateProxy.self)}// Register known implementationsstaticfuncregisterKnownImplementations(){self.register {WKNavigationDelegateProxy(webView:$0)}}staticfunccurrentDelegate(for object:WKWebView)->WKNavigationDelegate?{return object.navigationDelegate
    }staticfuncsetCurrentDelegate(_ delegate:WKNavigationDelegate?, to object:WKWebView){
        object.navigationDelegate = delegate
    }}

III. Wrap các function trong WKNavigationDelagate vào Observable:

Các function methodInvoked sẽ trả về một array dạng Array<Any> chứa các parameters của function trong WKNavigationDelgate được gọi tới. Tại mỗi function chúng ta sẽ sử dụng func castOrThrow<T> để parse về kiểu dữ liệu mong muốn.

extensionReactivewhereBase:WKWebView{funccastOrThrow<T>(_ resultType:T.Type,_ object:Any)throws->T{guardlet returnValue = object as?Telse{throwRxCocoaError.castingError(object: object, targetType: resultType)}return returnValue
    }var navigationDelegate:DelegateProxy<WKWebView,WKNavigationDelegate>{RxWKNavigationDelegateProxy.proxy(for: base)}var didCommit:Observable<WKNavigation>{
        navigationDelegate.methodInvoked(#selector(WKNavigationDelegate.webView(_:didCommit:))).map { params intrycastOrThrow(WKNavigation.self, params[1])}}var didStartLoad:Observable<WKNavigation>{
        navigationDelegate.methodInvoked(#selector(WKNavigationDelegate.webView(_:didStartProvisionalNavigation:))).map { params intrycastOrThrow(WKNavigation.self, params[1])}}var didFinishLoad:Observable<WKNavigation>{
        navigationDelegate.methodInvoked(#selector(WKNavigationDelegate.webView(_:didFinish:))).map { params intrycastOrThrow(WKNavigation.self, params[1])}}var didFailLoad:Observable<(WKNavigation,Error)>{
        navigationDelegate.methodInvoked(#selector(WKNavigationDelegate.webView(_:didFail:withError:))).map { params inreturn(trycastOrThrow(WKNavigation.self, params[1]),trycastOrThrow(Error.self, params[2]))}}}

IV. Cách sử dụng:

let webview =WKWebView(frame:.zero)let disposeBag =DisposeBag()
        
        webview.rx.didCommit
            .subscribe(onNext:{ wkNavigation inprint("LOG + didCommit")}).disposed(by: disposeBag)
        
        webview.rx.didStartLoad
            .subscribe(onNext:{ wkNavigation inprint("LOG + didStartLoad")}).disposed(by: disposeBag)
        
        webview.rx.didFinishLoad
            .subscribe(onNext:{ wkNavigation inprint("LOG + didFinishLoad")}).disposed(by: disposeBag)
        
        webview.rx.didFailLoad
            .subscribe(onNext:{ wkNavigation, error inprint("LOG + didFailLoad")}).disposed(by: disposeBag)let urlRequest =URLRequest(url:URL(string:"https://tinhte.vn")!)
        webview.load(urlRequest)
LOG+ didStartLoad
LOG+ didCommit
LOG+ didFinishLoad

Nguồn: viblo.asia

Bài viết liên quan

Tấn Công Ứng Dụng Web: Mối Đe Dọa Hàng Đầu – Phần 2

viết lại nội dung này ” Phát hiện các cuộc tấn công Cross Site Scripting (XSS)

AI Chatbot 2025: Xu Hướng Tất Yếu Cho Doanh Nghiệp Dẫn Đầu

Giới thiệu AI chatbots đã trải qua một hành trình đáng kể, từ những công cụ t

Tấn Công Ứng Dụng Web: Mối Đe Dọa Hàng Đầu – Phần 1

Tấn công web là gì? Ứng dụng web là các ứng dụng cung cấp dịch vụ cho người

SEO Mũ Trắng, Mũ Đen, Mũ Xám: Hiểu Biết và Lựa Chọn Phù Hợp

SEO Mũ Trắng, Mũ Đen, Mũ Xám: Hiểu Biết và Lựa Chọn Phù Hợp Trong kỷ nguyên s