Skip to main content

Dùng thư viện RXSWIFT để cải tiến hiệu suất cho dự án iOS của bạn — phần 2


RxSwift
  1. Observable :
    - Là một sequence , nó bắn các event qua các khoảng thời gian khác nhau. Event có thể chứa value Int ,String , Custom type hay là một gesture, 1 tap khi nhấn button.

- Life cycle của nó như sau : khi emit 1 event đó là next, Khi complete or error là kết thúc 1 stream.

Obserable Cycle
-Observable vs observer
// OBSERVABLE //
let observable = Observable<String>.create { (observer) -> Disposable in
    DispatchQueue.global(qos: .default).async {
        Thread.sleep(forTimeInterval: 10)
        observer.onNext("Hello dummy 🐣")
        observer.onCompleted()
    }
    return Disposables.create()
}  
      
// OBSERVER //
observable.subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)
Ví dụ trên bạn có thể thấy observable là cái sẽ emit ra event, còn observer là cái nhận event.
-Tạo một observable
// ========1.Tạo từ những giá trị cho trước======= //
Observable.of(1, 2, 3, 4, 5, 6)let observable = Observable<String>.create { (observer) ->  Disposable in
    observer.onNext("merge : 🎁")
    return Disposables.create()
}// =========2.Khi get API dùng URLSession ===========//func getRepositories(githubId:String) -> Observable<[Repository]> {
    guard let url = NSURL(string: "https://api.github.com/users/\(githubId)/repos")
        else { return Observable.just([]) }
    return URLSession.sharedSession
        .rx_JSON(NSURLRequest(URL: url))
        .retry(3)
        .map {
            var data = [Repository]()if let items = $0 as? [[String: AnyObject]] {
                items.forEach {
                    guard let name = $0["name"] as? String,
                        let url = $0["url"] as? String
                        else { return }data.append(Repository(name: name, url: url))
                }
            }return data
    }
}//==============3.Từ Subject vs Variable========== //
struct Student {
   var score: Variable<Int>
}
let student = PublishSubject<Student>()
student.asObservable()
.flatMap {
        $0.score.asObservable()
    }
.subscribe(onNext: {
        print($0)
    })
.addDisposableTo(disposeBag)
-Subscribing : dùng hàm subscribe để đăng kí nhận event
//Subscribe tất cả event
observable.subscribe { event in
  print(event)
}//Subscribe on next
observable.subscribe(onNext: { element in
  print(element)
})//Subscribe on next vs complete
observable.subscribe(onNext: { element in
      print(element)
},onCompleted: {
      print("Completed")
})//Subscribe với next,complete,error
.subscribe(
    onNext: {
        print($0) },
    onError: {
        print($0) },
    onCompleted: {
        print("Completed") 
    }
)
-Dispose : dùng để clean up, giải phóng 1 observable
Dispose Bag : trả về 1 loại giống ARC , tự giải phóng khi Owner đang subscribe vào hàm deinit giải phóng bộ nhớ.
Dispose Bag
// Chúng ta sẽ dispose bằng hàm, khi nào chúng ta cần dừng
subscription.dispose()// Dùng 1 instance DisposeBag, sẽ tự động gọi dispose khi class hiện tại đang cần subscribe đã deinitlet disposeBag = DisposeBag()
Observable.of("A", "B", "C")
.subscribe { 
   print($0) 
}
.disposed(by: disposeBag)
-Với các observable dùng hàm "create" để tạo sẽ return 1 dispose
return Disposables.create(with: {
    //Clean up
    connection.close()
    database.closeImportantSomething()
    cache.clear()
})Observable<String>.create { observer in
    observer.onNext("1")
    return Disposables.create()
}
.subscribe(
    onNext: {
       print($0) },
    onError: {
       print($0) },
    onCompleted: {
       print("Completed") },
    onDisposed: {
       print("Disposed") }
)
//.disposed(by: disposeBag)
+ Nhưng với dispose kiểu này thì phải gọi complete or error nó mới dispose => leak memory
+ Còn dùng .disposed(by: disposeBag) => Sẽ luôn luôn được giải phóng và không gây leak memory
-Chúng ta có 2 loại observable là HOT vs COLD
+ HOT : observable chỉ bắt đầu thực hiện khi có 1 observer subscribe.
Dùng trong các loại : Variables / properties / constants, tap coordinates, mouse coordinates, UI control values, current time.
+ COLD : observable luôn luôn thực hiện bất kể ko có 1 observer subscribe nào.
Dùng trong các loại : Async operations, HTTP Connections, TCP connections, streams.
2.SubjectsLà một loại đặc biệt có thể là 1 observable(output) và cũng là 1 observer(input) . Có 4 loại subjects :
+ PublicSubject : bắt đầu rỗng và chỉ bắn ra event khi có subscribe.
+ BehaviorSubject : bắt đầu với giá trị khởi tạo và sẽ bắn kèm cho subscribe mới với 1 event gần nhất.
+ ReplySubject : giống behavior, và có thể para : buffersize để xác định số lập lại.
+ Variable : wrap một BehaviorSubject và lưu trữ giá trị như một trạng thái(state).Để observer thì bạn dùng từ khoá asObservable.
Sơ đồ sau sẽ giải thích cho các bạn rõ sự khác nhau.
PublicSubject vs BehaviorSubject vs ReplySubject
-PublicSubject : bắt đầu rỗng và chỉ bắn ra event khi có subscribe, nó bỏ qua các phần tử đã bắn trc đó trước khi nhận 1 subscibe
//Khởi tạo 1 PublishSubject  
let subject = PublishSubject<String>()//Chuyển PublishSubject -> Observable
let observable : Observable<String> = subject //Chưa có 1 subscribe nào -> onNext ko có tác động
 subject.onNext("bỏ qua") //Bắt đầy subscribe 
 observable
 .subscribe(onNext: { text in
         print(text)
     })
 .addDisposableTo(disposeBag) // Khi trong hàng đợi subscribe có ít nhất 1 cái
 subject.onNext("Start!")
-BehaviorSubject : bắt đầu với giá trị khởi tạo và sẽ bắn kèm cho subscribe mới với 1 event gần nhất.Chỉ nhận mới nhất và mới nhất gần nhất
let subjectBehavior = BehaviorSubject<String>(value: "Gia tri ban dau")
let observable : Observable<String> = subjectBehaviorsubjectBehavior.onNext("event1")
subjectBehavior.onNext("event2")
subjectBehavior.onNext("event3") // mới nhất gần nhấtobservable
.subscribe(onNext: { text in
        print(text)
    })
.addDisposableTo(disposeBag)subjectBehavior.onNext("event4") // mới nhất
 
// event3 
// event4
-ReplySubject : giống behavior, và có thể para : buffersize để xác định số lập lại ngoài cái mới nhất
// Định nghĩa ReplaySubject với số lần lặp lại là 2
let subjectReply = ReplaySubject<String>().create(bufferSize: 2)
let observable : Observable<String> = subjectReplysubjectReply.onNext("event1")
subjectReply.onNext("event2") // mới nhất lần 2
subjectReply.onNext("event3") // mới nhất lần 1observable
.subscribe(onNext: { text in
        print(text)
})
.addDisposableTo(disposeBag)subjectReply.onNext("event4") // mới nhất// event 2
// event 3
// event 4
-Variable : wrap một BehaviorSubject, nó giống BehviorSubject ở chỗ sẽ bắt các event mới nhất và gần mới nhất , lưu trữ giá trị như một trạng thái(state).Variable có property value có thể gắn giá trị vào đó.Để observer thì bạn dùng từ khoá asObservable.
let variable = Variable<Int>(0)
print("Before first subscription ---")let variable1 = variable.asObservable()
    .subscribe(onNext: { n in
        print("First \(n)")
    }, onCompleted: {
        print("Completed 1")
})print("Before send 1")
variable.value = 1//Before first subscription ---
//First 0
//Before send 1
//First 1
Ok , phần này mình đã trình bày cho các bạn về Observable vs Subject trong RXSwift. Trong phần sau minh sẽ nói về các toán tử (operator), giúp kết hợp các observable theo các chức năng khác nhau.

Comments

Popular posts from this blog

MVVM và VIPER: Con đường trở thành Senior

Trong bài viết trước chúng ta đã tìm hiểu về MVC và MVP để ứng dụng cho một iOS App đơn giản. Bài này chúng ta sẽ tiếp tục ứng dụng 2 mô hình MVVM và VIPER . Nhắc lại là ứng dụng của chúng ta cụ thể khi chạy sẽ như sau: Source code đầy đủ cho tất cả mô hình MVC, MVP, MVVM và VIPER các bạn có thể download tại đây . MVVM MVVM có thể nói là mô hình kiến trúc được rất nhiều các cư dân trong cộng đồng ưa chuộng. Điểm tinh hoa của kiến trúc này là ở ViewModel , mặc dù rất giống với Presenter trong MVP tuy nhiên có 2 điều làm nên tên tuổi của kiến trúc này đó là: ViewModel không hề biết gì về View , một ViewModel có thể được sử dụng cho nhiều View (one-to-many). ViewModel sử dụng Observer design pattern để liên lạc với View (thường được gọi là binding data , có thể là 1 chiều hoặc 2 chiều tùy nhu cầu ứng dụng). Chính đặc điểm này MVVM thường được phối hợp với các thư viện hỗ trợ Reactive Programming hay Event/Data Stream , đây là triết lý lập trình hiện đại và hiệu

Alamofire vs URLSession

Alamofire vs URLSession: a comparison for networking in Swift Alamofire and URLSession both help you to make network requests in Swift. The URLSession API is part of the foundation framework, whereas Alamofire needs to be added as an external dependency. Many  developers  doubt  whether it’s needed to include an extra dependency on something basic like networking in Swift. In the end, it’s perfectly doable to implement a networking layer with the great URLSession API’s which are available nowadays. This blog post is here to compare both frameworks and to find out when to add Alamofire as an external dependency. Build better iOS apps faster Looking for a great mobile CI/CD solution that has tons of iOS-specific tools, smooth code signing, and even real device testing? Learn more about Bitrise’s iOS specific solutions! This shows the real power of Alamofire as the framework makes a lot of things easier. What is Alamofire? Where URLSession can be found within the s

Fileprivate vs private: Giải thích sự khác biệt

Fileprivate vs private in Swift: The differences explained Fileprivate and private are part of the access control modifiers in Swift. These keywords, together with internal, public, and open, make it possible to restrict access to parts of your code from code in other source files and modules. The private access level is the lowest and most restrictive level whereas open access is the highest and least restrictive. The documentation of Swift will explain all access levels in detail to you, but in this blog post, I’m going to explain the differences between two close friends: fileprivate and private. Build better iOS apps faster Looking for a great mobile CI/CD solution that has tons of iOS-specific tools, smooth code signing, and even real device testing? Learn more about Bitrise’s iOS specific solutions! Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level. This will improve readability and mak