Month: July 2020

  • Tips to ask a good question or make a better request

    Tips to ask a good question or make a better request

    Gần đây, mình thấy rất nhiều các bạn trẻ gặp phải các lỗi cơ bản về kỹ năng giao tiếp. Cụ thể là cách đặt câu hỏi/đưa ra yêu cầu trợ giúp. Dẫn đến việc có khá nhiều questions/requests không nhận được câu trả lời, hoặc câu trả lời không đúng như mong muốn của người hỏi.

    Để tránh rơi vào những tình huống như vậy, mình sẽ chỉ cho các bạn một số tips dựa trên kinh nghiệm làm việc với nhiều đối tác, khách hàng cũng như đồng nghiệp trong công ty của mình. Hy vọng sẽ giúp được các bạn phần nào.

    Đầu tiên, bạn cần nắm rõ vấn đề mà mình cần hỏi đã. Hãy tự trả lời những câu hỏi sau trước nhé:

    1. Context/Background (bối cảnh) là gì? Ví dụ:
      • Ai là người phát hiện (detect) ra?
      • Xảy ra ở giai đoạn (phase) nào của dự án?
    2. Problem/Issue (vấn đề) cụ thể là gì?
      • Liên quan đến tính năng (feature/module) nào trong requirements?
      • Tần xuất (frequency) xảy ra là bao nhiêu?
      • Đang hoặc có thể gây ra những ảnh hưởng (impact) gì?
      • Bạn đánh giá mức độ nghiêm trọng (severity) này ra sao (critical, high)?
    3. What have you done/Investigated Actions của bạn là gì rồi?
      • Bạn đã thực hiện tìm kiếm (search/research) thông tin trên Internet chưa?
      • Bạn đã thảo luận với các thành viên có kinh nghiệm hơn trong chính dự án (your team) chưa?
      • Bạn đã thử bao nhiêu phương án (try how many solutions) để giải quyết vấn đề rồi? Cụ thể là gì, kết quả (result) của từng phương án ra sao, đang bị tắc chỗ nào?

    Sau khi đã nắm khá rõ vấn đề và thử một số cách rồi nhưng vẫn chưa ra kết quả, thì mới đi tìm kiếm thêm sự giúp đỡ bạn nhé. Bây giờ, bạn cần xác định thêm:

    1. Right People, người/nhóm cụ thể bạn cần hỏi/tìm kiếm sự trợ giúp là ai? Đừng quăng vấn đề của mình vào 1 group quá lớn hoặc send email tới quá nhiều người mà mong có sự phản hồi nha.
    2. TODO List, những công việc cần làm tiếp theo là gì? Người bạn đang hỏi có thể giúp được gì trong đó?
      • TODO list để giải quyết vấn đề trên có thể là cả tá items, nên bạn cần xác định rõ những items nào bạn và team có thể xoay sở tiếp được, những items nào thực sự vượt quá năng lực/khả năng thì mới nhờ nhé.
    3. Bạn mong muốn nhận được phản hồi hay sự trợ giúp vào lúc nào? Đừng đưa ra một cái expected due time quá gấp, trong trường hợp vấn đề của bạn thực sự urgent thì hãy hỏi xem khi nào người trợ giúp bố trí được thời gian để bạn trình bày trực tiếp với họ nhé.

    Tóm lại, trước khi hỏi hay tìm kiếm sự giúp đỡ, hãy chắc chắn rằng bạn đã hiểu rõ (understand clearly) vấn đề của mình. Và bóc tách (break) vấn đề ra càng nhỏ càng tốt (as small as possible). Khi đó, bạn sẽ rất ngạc nhiên là sao vấn đề to tát của mình nó lại trở nên simple như thế và từ đó bạn có thể ask the Right People the Right Questions.

  • Debug Conflict Constraint iOS

    Debug Conflict Constraint iOS

    Có thể bạn đã từng gặp lỗi constraint bị breaking với kiểu log như thế này:

    Thường thì Xcode sẽ tự loại bỏ 1 constraint để view không bị conflict nữa. Điều này sẽ dẫn đến UI hiển thị trên màn hình đúng hoặc không, tùy thuộc vào việc Xcode loại bỏ constraint nào.

    Tuy nhiên, kể cả trong trường hợp UI hiển thị đúng, thì chúng ta vẫn nên đi fix cái lỗi này.

    Đối với những màn hình phức tạp, nhiều subview, việc biết view nào đang bị lỗi constraint là khó có thể phán đoán được.

    Vì vậy ở bài viết này, hãy cùng nhau đi đọc đống log kia để biết view nào đang bị conflict constraint 🙂

    Tìm xem view nào bị lỗi bằng cách đọc địa chỉ

    Để í đến dòng log sau:

    Đoạn log này hướng dẫn rằng code sẽ recover bằng cách loại bỏ constraint 0x60000336d7c0 của view có địa chỉ 0x7fccafe06a10.
    Giờ thì bắt đầu đi tìm view có địa chỉ 0x7fccafe06a10:

    • Chọn Show Debug Navigator (Command + 7).
    • Chọn View Memory Graph Hierachy
    • Nhập địa chỉ của View cần tìm vào phần Filter.
    • Chọn vào View có địa chỉ cần tìm, Xcode sẽ hiển thị kết quả như sau:
    • Click chuột phải vào View, chọn Quick Look để xem đó là View nào:
    • Với Quick Look, Xcode sẽ hiển thị View đang bị conflict constraint:

    Đổi màu background của View bằng lldb:

    Nếu trong trường hợp có quá nhiều View giống nhau, và bạn vẫn chưa thể xác định đó là view nào?
    -> Dùng lldb để đổi màu background view đó để có thể xác định dễ hơn.

    Đầu tiên, pause chương trình lại và thực hiện lệnh sau ở cửa sổ lldb:

    expression [(UIView*)0x7fccafe06a10 setBackgroundColor:[UIColor redColor]]
    • Với lệnh này, chọn Quick Look với View vừa rồi thì View đã chuyển sang màu đỏ rồi, nhưng vẫn chưa hiển thị trên màn hình simulator/device.
    • Để View đổi màu ngay lập tức trên simulator/device, thực hiện tiếp 1 câu lệnh sau:
    expression (void)[CATransaction flush]

    OK, khi đó thì View bị lỗi constraint đã ngay lập tức đổi màu rồi.

    Xem tất cả constraint của View:

    • Mở Debug View Hỉeachy.
    • Tìm và chọn view bị lỗi constraint.
    • Chọn Show the size inspector (Option + Command + 5)
    • Khi đó, ở mục Constraint thì sẽ hiển thị tất cả constraint đang gắn với view đó. Cuối cùng thì chỉ cần bỏ đi constraint nào không cần thiết là được.

    Vừa leading, vừa centerX, vừa set width gây ra bị conflic constraint. Bỏ width constraint hoặc leading constraint tùy vào mục đích.

    Tham khảo: https://medium.com/ios-os-x-development/dynamically-modify-ui-via-lldb-expression-1b354254e1dd

  • Bluetooth, Beacon & iOS CoreBluetooth

    Bluetooth, Beacon & iOS CoreBluetooth

    Bluetooth

    Bluetooth, một công nghệ không dây năng lượng thấp, tầm ngắn ra đời từ những ngày đầu của điện thoại di động, được sử dụng rộng rãi và có mặt trong hàng tỉ thiết bị và vật dụng hàng ngày. Bluetooth tạo ra một thế giới không cần dùng dây và là hình thức đầu tiên kết nối các thiết bị khác nhau, sản sinh ra những tính năng và hành vi tiêu dùng mới.

    Bluetooth low energy (BLE)

    Bluetooth Low Energy là chuẩn kết nối không dây hướng tới các ứng dụng tiết kiệm năng lượng (giải thích: việc truyền không dây thường tốn nhiều năng lượng, do đó, người ta cố gắng nghiên cứu những công nghệ, kỹ thuật sao cho việc truyền nhận dữ liệu không dây ít tiêu tốn năng lượng nhất có thể và thế là BLE ra đời).​

    Bluetooth version

    Trong quá trình phát triển của Bluetooth, Bluetooth SIG đã công bố nhiều version và vẫn đang tiếp tục phát triển các version mới

    • Bluetooth 1.x: Phiên bản Bluetooth đầu tiên, gần như không còn được sử dụng. Có tốc độ lý thuyết là 1Mbps – tốc độ này được giọi là Basic rate (BR).
      Capability : BR​
    • Bluetooth 2.x: Phiên bản nâng cấp của version 1.x cho tốc độ truyền tải lý thuyết cao hơn – 3 Mbps – tốc độ này được gọi là Enhanced data rate (EDR). Lưu ý: EDR là optional, thiết bị hỗ trợ Bluetooth 2.x vẫn có thể kết nối với tốc độ BR.
      Capability: BR + EDR​
    • Bluetooth 3.x: Hỗ trợ việc thay đổi lower layer. Các ứng dụng có lower layer thiết kế theo chuẩn của Bluetooth có thể chuyển qua sử dụng của chuẩn của giao thức 802.1 với tốc độ truyền tải dữ liệu cao hơn. Bluetooth 3.x có thể đạt tốc độ truyền tải lý thuyết lên đến 23Mbps – tốc độ này gọi là High speed (HS) và là một option của thiết bị hỗ trợ Bluetooth 3.x.
      Capability: BR + EDR + HS​
    • Bluetooth 4.x: Bổ sung thêm chuẩn giao tiếp Bluetooth Low Energy. Với ưu điểm là thu thập dữ liệu từ các thiết bị có tần số gửi data thấp, mỗi lần gửi một lượng data nhỏ (ví dụ: heart rate sensor, temperature sensor, humid sensor, …).
      Capability: BR + EDR + HS + LE​
    • Bluetooth 5.x: Go Faster. Go Further. Highlight Improvement: Range, Speed, bandwidth. Khoảng cách truyền dữ liệu lên đến 120m so với 30m của version 4.x. Tốc độ truyền tối đa của Bluetooth 5 low energy theo lý thuyết là 2Mbps, gấp đôi Bluetooth Low Energy 4.2 mà không làm tăng power consumption. Capability trong trường hợp này là khả năng hỗ trợ của version Bluetooth. Ví dụ như thiết bị mình mua về, nhà sản xuất kêu nó hỗ trợ Bluetooth 2.0 thì bạn không thể nào mong nó có khả năng kết nối với thiết bị hỗ trợ Bluetooth 3.0 với tốc độ HS. Tuy nhiên hai thiết bị này vẫn có thể kết nối với nhau với tốc độ EDR Note: Refer wiki dưới đây biết version bluetooth mà iOS device đang sử dụng:
      https://en.wikipedia.org/wiki/List_of_iOS_devices

    Các kiểu thiết bị Bluetooth

    • Thiết bị chỉ hỗ trợ Bluetooth Smart (Bluetooth Low Energy) không thể kết nối trực tiếp tới thiết bị chỉ hỗ trợ Bluetooth Classic (Bluetooth ít tiết kiệm năng lương)

    • Thiết bị hỗ trợ Bluetooth Smart Ready có thể kết nối trực tiếp với cả thiết bị hỗ trợ Bluetooth Low Energy và Bluetooth Classic. Ví dụ như iphone sẽ là 1 thiết bị Bluetooth smart ready và nó có thể kết nối với tai nghe không dây thông qua chuẩn Bluetooth Classic và cũng có thể kết nối với smart watch thông qua chuẩn Bluetooth Low Energy.

    Beacon

    Beacons là các máy phát không dây nhỏ, sử dụng công nghệ Bluetooth Low Energy để gửi tín hiệu đến các thiết bị thông minh khác gần đó. Đây là một trong những phát triển mới nhất trong công nghệ vị trí và tiếp thị gần (Proximity Marketing). Nói một cách đơn giản, chúng kết nối và truyền thông tin đến các thiết bị thông minh giúp cho việc tìm kiếm và tương tác dựa trên vị trí trở nên dễ dàng và chính xác hơn.

    Ưu thế lớn nhất của BLE là tiết kiệm năng lượng, cho phép beacons truyền thông tin liên tục lên đến 2-3 năm chỉ với một viên pin nhỏ. Khoảng cách truyền BLE cũng lên đến 100m như Classic Bluetooth.

    BLE có hai chế độ trao đổi thông tin:

    Advertising: chỉ truyền một chiều

    Connecting: trao đổi hai chiều

    Beacons chỉ sử dụng chế độ truyền advertising (chỉ gửi thông tin một chiều). Beacons theo một chu kỳ sẽ phát thông tin quảng bá để các thiết bị khác như smartphone nhận. Beacons có thể phát với chu kỳ từ 20ms đến 10s, chu kỳ càng dài thì thời lượng pin càng lâu.

    Thiết bị Beacon rất đơn giản. Mỗi thiết bị chứa CPU, radio và pin, và nó hoạt động bằng cách liên tục phát ra một mã định danh (ID) . Mã nhận dạng này được chọn bởi thiết bị của bạn, thường là điện thoại di động và đánh dấu một vị trí quan trọng trong môi trường của bạn. Mã định danh là số ID duy nhất mà điện thoại thông minh của bạn nhận ra là duy nhất cho Beacon. Sau khi kết nối, Beacon sẽ thực hiện bất kỳ chức năng nào nó đã được lập trình bao gồm : quảng cáo, điều hướng, theo dõi…

    Chúng ta có thể xem xét ví dụ điển hình về quảng cáo trong Mall:

    Bước 1: Người dùng tìm kiếm ở Google về “Black Shoes”
    Bước 2: Quảng cáo tìm kiếm Google của bạn xuất hiện.
    Bước 3: Người dùng nhấp vào quảng cáo tìm kiếm, duyệt sản phẩm, sau đó đóng điện thoại của họ.
    Bước 4: Người dùng này quyết định họ muốn thử giày trước khi mua, vì vậy họ bước vào cửa hàng của bạn.
    Bước 5: Khi họ vào cửa hàng, điện thoại của họ nhận một số nhận dạng ID từ Beacon của cửa hàng của bạn.
    Bước 6: Beacon nhận ra rằng điện thoại này giống với điện thoại đã nhấp vào quảng cáo tìm kiếm của bạn và liên kết dữ liệu này với tài khoản Google Ads của bạn dưới dạng chuyến thăm cửa hàng trên mạng.

    Bằng cách ghi nhật ký lượt truy cập cửa hàng thực tế từ quảng cáo tìm kiếm của bạn, công nghệ này sẽ giúp bạn hiểu được tác động và hiệu quả của quảng cáo tìm kiếm của bạn. Nếu bạn thấy họ đang thu hút rất nhiều lượt truy cập vào cửa hàng của bạn, bạn có thể muốn đầu tư nhiều hơn vào tìm kiếm.

    Beacons gửi dữ liệu gì?

    Một gói tin để các thiết bị đọc được phải tuân theo các chuẩn đã được định trước, trước tiên là gói dữ liệu advertising. Một gói tin advertising có độ dài lên đến 47 bytes.

    • Preamble (1 byte)
    • Access Address (4 bytes) – 8E 89 BE D6
    • PDU Header (2 bytes)
    • PDU MAC address (6 bytes)
    • PDU Data (0-31 bytes)
    • CRC (3 bytes)

    Phân loại Beacon

    IBeacon Là giao thức BLE được Apple đưa ra 12/2013, đây là một bộ giao thức chính thức đầu tiên về BLE, đa số mọi beacons đều hỗ trợ. Giao thức này được hỗ trợ chỉ trên iOS, nhưng hiện nay có thể tìm rất nhiều hàm API hỗ trợ tìm kiếm các iBeacon trên Android. Cần có một ứng dụng để tìm kiếm beacons và thực hiện các thao tác với chúng.

    • iBeacon hỗ trợ hai kiểu tương tác, giám sát (monitoring) và vùng phủ
      (ranging). Với chế độ giám sát ứng dụng sẽ cảnh báo ngay cả khi ứng
      dụng đã tắt. Khác chế độ giám sát, chế độ cự ly chỉ hoạt động khi ứng
      dụng đang chạy.
    • Với iBeacon thì các beacon sẽ phát ra dữ liệu gì?, chúng phát ba
      thông tin UUID, Major, và Minor. Sẽ không bao giờ có hai beacon cùng
      UUID, Major, và Minor.

    Eddystone Là giao thức BLE do Google công bố 7/2015, được hỗ trợ chính thức trên cả hai nền tảng iOS và Android. Là một giao thức mở và hỗ trợ nhiều gói tin khác nhau. Chỉ hỗ trợ một kiểu tương tác cơ bản, gần giống với vùng phủ của iBeacon.

    Các gói tin của Eddystone gồm có:

    • Eddystone-UID: gần giống gói tin của iBeacon, gồm các thông tin
      Namespace (chức năng giống UUID của iBeacon) và Instance (chức năng
      giống Major và Minor của iBeacon)
    • Eddystone-URL: gửi thông tin một đường dẫn site . Với gói tin này
      trên điện thoại sẽ mở site và ko cần cái ứng dụng.
    • Eddystone-TLM: là gói tin gửi các thông tin của beacons như điện áp
      pin, nhiệt độ, số gói tin đã gửi, và thời gian bật beacons. Gói tin
      này sẽ gửi với chu kỳ dài hơn hai gói trên.

    Ứng dụng của Beacon

    Công nghệ Beacon còn rất nhiều mở rộng trong tương lai, nên việc sử dụng nó vẫn đang được phát hiện. Hiện tại, trọng tâm chính vẫn là trong lĩnh vực điều hướng và và quảng cáo. Đây là nơi bạn thấy các công ty đầu tư mạnh vào thời điểm này.

    •Sản xuất
    •Quản lý chuỗi cung ứng
    •Bán buôn / bán lẻ / thương mại
    •Nhà hàng, khách sạn
    •Du lịch
    •Giáo dục
    •Chăm sóc sức khỏe

    Core bluetooth là gì ?

    Core Bluetooth là một framework cung cấp các lớp cần thiết cho ứng dụng iOS và MacOS có thể giao tiếp với các thiết bị có hỗ trợ công nghệ không dây bluetooth được trang bị các chuẩn low energy (LE) và Basic Rate / Enhanced Data Rate (BR/EDR) .

    Central, Peripheral

    Có hai đối tượng chính trong quá trình giao tiếp Bluetooth: central và peripheral.

    • Một peripheral thường là một đối tượng có chứa dữ liệu, và các thiết
      bị khác sẽ cần sử dụng dữ liệu đó.
    • Một central thường là một đối tượng mà sử dụng thông tin được cung
      cấp bởi peripheral để thực hiện một nhiệm vụ nào đó.

    Ví dụ: Một chiếc máy đo nhịp tim (peripheral) chứa những thông tin hữu ích mà các ứng dụng trên điện thoại và máy tính (central) cần để hiển thị nhịp tim của người sử dụng theo một cách dễ hình dung trên màn hình.

    Central

    Central phát hiện và kết nối tới các Peripheral đang advertising

    • Peripheral phát tán một vài dữ liệu của chúng ở dạng advertising packet. Một advertising packet là như một gói dữ liệu nhỏ chứa những thông tin mà peripheral phải cung cấp để nhận dạng, ví dụ như tên của peripheral và chức năng chính của nó. Ví dụ, một máy điều hòa nhiệt độ phải advertise rằng chúng cung cấp nhiệt độ hiện tại của căn phòng. Trong công nghệ Bluetooth, advertising là cách chính để peripheral thể hiện sự có mặt của nó.

    • Một central, mặt khác, sẽ quét và lắng nghe bất cứ thiết bị peripheral nào đang advertising thông tin mà nó muốn, sau đó có thể yêu cầu quyền truy cập tới thiết bị đó.

    Dữ liệu của một Peripheral được cấu trúc như thế nào ?

    Mục đích của việc kết nối tới peripheral là dò xét và tương tác với với dữ liệu mà nó cung cấp, và trước khi làm vậy, sẽ tốt hơn nếu bạn hiểu dữ liệu của peripheral được cấu trúc ra sao.

    • Peripheral có thể bao gồm một hoặc nhiều service hoặc cung cấp thông tin hữu ích về cường độ tín hiệu kết nối. Một service là một tập dữ liệu và hành vi đi kèm để thực hiện một chức năng hay một tính năng của thiết bị. Ví dụ, một service của máy đo nhịp tim là đưa ra dữ liệu nhịp tim từ bộ cảm biến.

    • Service được tạo nên từ các characteristic hoặc từ việc sử dụng các service khác. Một characteristic cung cấp những thông tin chi tiết hơn về một service của peripheral. Ví dụ, service nhịp tim vừa mô tả ở trên có thể bao gồm một characteristic mô tả vị trí hướng cơ thể của bộ cảm biến và một characteristic khác trao đổi dữ liệu tính toán nhịp tim. Hình dưới đây cung cấp một cấu trúc có thể có về service và characteristic của một máy đo nhịp tim.

    Central dò xét và tương tác với dữ liệu của Peripheral

    • Sau khi central thiết lập kết nối thành công tới peripheral, nó có thể thấy được toàn bộ service và characteristic mà peripheral cung cấp (dữ liệu lúc advertising có thể chỉ là một phần của những service hiện có).

    • Một central có thể tương tác với service của peripheral bằng việc đọc và ghi các characteristic của service đó. Ví dụ, ứng dụng của bạn có thể yêu cầu thông tin về nhiệt độ phòng từ một máy điều hòa nhiệt độ hoặc cung cấp cho máy điều hòa nhiệt độ một giá trị để thiết lập nhiệt độ phòng.

    Khi thiết bị của bạn đóng vai trò là Central

    Phần lớn các hoạt động khi xử lý với Bluetooth của bạn nằm ở phía central

    Ở phía central, một thiết bị local central được thể hiện bởi một đối tượng CBCentralManager. Đối tượng này được sử dụng để quản lý việc phát hiện và kết nối tới thiết bị remote peripheral (thể hiện bởi đối tượng CBPeripheral), bao gồm việc quét, phát hiện, và kết nối tới peripheral đang advertising.

    Thiết bị central sẽ có nhiệm vụ tìm và kết nối tới các peripheral, sau đó sẽ đọc và tương tác với dữ liệu của peripheral đó.

    • Khởi tạo central manager object
    • Tìm kiếm và kết nối tới một peripheral nào đó đang phát sóng.
    • Đọc dữ liệu trên peripheral sau khi kết nối thành công.
    • Gửi các request đọc và ghi một characteristic nào đó của các dịch vụ trong peripheral.
    • Đăng ký nhận thông báo khi một characteristic cập nhật.

    Refer:
    https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonCentralRoleTasks/PerformingCommonCentralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH3-SW1

    Khi thiết bị của bạn đóng vai trò là Peripheral

    Máy Mac sử dụng MacOS 10.9 trở lên, thiết bị iOS sử dụng iOS 6.0 trở lên có chứa các tính năng để tương tác như một peripheral, cung cấp dữ liệu cho các thiết bị khác, bao gồm các máy Mac, iPhone và iPad khác. Khi thiết lập thiết bị của bạn để thực thi trong vai trò peripheral, bạn đang thực hiện những hoạt động ở phía peripheral trong việc giao tiếp giữa các thiết bị Bluetooth.

    • Ở phía peripheral, một thiết bị local peripheral được thể hiện bởi đối tượng CBPeripheralManager. Đối tượng này được sử dụng để quản lý các service công khai bên trong cơ sở dữ liệu về service và characteristic của thiết bị local peripheral, và có nhiệm vụ advertising các service này tới các thiết bị remote central (thể hiện bởi đối tượng CBCentral). Đối tượng peripheral manager còn được sử dụng để trả lời các yêu cầu đọc và ghi từ remote central.

    Thiết bị peripheral có nhiệm vụ cung cấp, phát tán các service của nó, và trả lời các request từ central.

    • Khởi tạo một peripheral manager object.
    • Thiết lập các service và characteristic trên thiết bị.
    • Publish các service và characteristic tới database của thiết bị.
    • Phát tán các service.
    • Trả lời các yêu cầu đọc và ghi từ các central được kết nối.
    • Gửi các giá trị của characteristic cho các central đã đăng ký (subscribe).

    Refer:
    https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonPeripheralRoleTasks/PerformingCommonPeripheralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH4-SW1

    Lời kết

    Qua bài viết trên đây hi vọng mọi ngừời sẽ nắm được những thông tin cơ bản của bluetooth cũng như các ứng dụng của nó tới đời sống, ngoài ra các bạn hãy code demo về corebluetooth như guide của apple mình đã refer link ở trên nhé.

  • [RxSwift] Traits

    Contents

    • Traits là gì?
    • Các loại Traits
      • Single
      • Completable
      • Maybe

    Traits là gì?

    Traits là observables nhưng với 1 phạm vi hành vi hẹp hơn so với các Observables thông thường.

    Lợi ích của Traits:

    • Vì phạm vi hẹp hơn, nên khi sử dụng Traits thì sẽ làm cho người đọc clear hơn về í nghĩa của task.
    • Traits luôn được observe và subcribe trên Main.

    Các loại Traits:

    • Trait trong RxSwift gồm 3 loại, đó là: Single, Completable

    Single:

    • Single sẽ chỉ emit ra duy nhất 1 event, và event đó phải thuộc 1 trong 2 kiểu .success(value) hoặc .error.
    • .success(value) về bản chất là sự kết hợp của .next và .complete event của Observable.
    • Sau khi emit event, single sẽ tự terminate.

    Demo

    enum DevideError: Error {
        case divideByZero
    }
    func divide(number1: Int, number2: Int) -> Single<Int> {
        return Single<Int>.create(subscribe: { observer in
            if number2 == 0 {
                 observer(.error(DevideError.divideByZero))
            } else {
                 let result = number1 / number2
                 observer(.success(result))
            }
            return Disposables.create()
        })
    }
    divide(number1: 10, number2: 2)
         .subscribe { (event) in
              switch event {
               case .success(let result):
                    print(result)
               case .error( let error):
                    print(error)
          }
    }

    Vì number2 khác 0, nên khi thực hiện hàm divide 10 cho 2 thì sẽ trả về 1 Single và nó sẽ emit ra .success(5).

    Completable:

    • Completable sẽ chỉ emit ra duy nhất 1 event, và event đó phải thuộc loại .completed hoặc .error.
    • Sau khi emit ra event thì sẽ tự động terminate.
    func divide(number1: Int, number2: Int) -> Completable {
        return Completable.create(subscribe: { observer in
            if number2 == 0 {
                observer(.error(DevideError.divideByZero))
            } else {
                let result = number1 / number2
                observer(.completed)
            }
            return Disposables.create()
        })
    }

    Maybe:

    • Maybe là sự kết hợp của Single và Completable. Nó có thể emit .success(value), .completed hoặc .error event.
    • Vẫn như 2 loại traits trên, Maybe sẽ chỉ emit ra 1 event duy nhất.
    • Sau khi emit ra event thì sẽ tự động terminate.
    Maybe cho phép bạn emit ra 3 loại event khác nhau.
    func divide(number1: Int, number2: Int) -> Maybe<Int> {
        return Maybe<Int>.create(subscribe: { observer in
            if number2 == 0 {
                observer(.error(DevideError.divideByZero))
            } else {
                let result = number1 / number2
                observer(.success(result))
            }
            return Disposables.create()
        })
    }

    Convert Traits thành Observable và ngược lại

    • Có thể convert 1 traits thành Observable đơn giản như sau:
    single.asObservable()
    • Việc convert từ Observable thành Traits cũng đơn giản như vậy:
    observable.asSingle()

    Tuy nhiên Traits thì chỉ emit ra 1 event, còn Observable của bạn thì có thể sẽ emit ra nhiều event. Vì vậy nếu convert 1 Observable emit ra nhiều event sang Traits thì traits đó sẽ emit ra error. Ví dụ như sau:

    let observable = Observable<String>.of("abc", "def")
    observable.asSingle().subscribe({ event in
        switch event {
        case .success(let value):
            print(value)
        case .error(let error):
            print(error)
        }
    })
    Lỗi được emit ra.

    Khi nào thì sử dụng Single, Completable & Maybe:

    Single:

    • Single có tác dụng cho những tiến trình chỉ chạy 1 lần và sẽ thành công với 1 value, hoặc sẽ bị error.
    • Ví dụ như download File, load data, …

    Completable:

    • Dùng cho những task mà bạn chỉ quan tâm xem nó thành công hay thất bại.
    • Ví dụ: Write file…

    Maybe:

    • Dùng cho những task có thể success hoặc fail, và tùy lúc sẽ emit ra 1 value khi success.
  • [RxSwift] Observable

    Contents

    • Observable là gì?
    • Các loại event
    • Khởi tạo Observable
    • Subcribe
    • Create Observable

    Observable là gì?

    • Observable là phần quan trọng nhất của RxSwift. có thể coi nó như 1 sequence, có tác dụng phát ra (emit) các event, và các object khác có thể lắng nghe những event đó.
    • Các event có thể đính kèm các giá trị với các kiểu dữ liệu quen thuộc như Int, String, … hay các kiểu dữ liệu mà bạn tự tạo ra.
    Hình trên là ví dụ cho các event 1, 2 ,3 lần lượt được emit ra theo thời gian.

    Các loại Event:

    Các event được emit ra thuộc 1 trong 3 loại:

    • next: Khi 1 Observable emit 1 element, thì nó được coi là 1 next event. Next event có thể đính kèm giá trị, và Observable có thể emit nhiều next event trong 1 life cycle của nó.
    • completed: Khi Observable hoàn thành việc emit event của mình, thì nó sẽ emit ra event completed và tự động terminate.
    • error: Khi Observable gặp lỗi trong quá trình emit event, thì nó sẽ emit ra event error và tự động terminate.

    Note:
    Tóm gọn lại, Observable có thể phát ra nhiều next event trong 1 life cycle; ngược lại thì Observable chỉ có thể phát ra 1 event complete hoặc error, sau đó sẽ tự hủy và không phát ra bất cứ event nào nữa.

    Khởi tạo Observable:

    of:

    let observable = Observable.of(1,2,3)
    let observable2 = Observable.of([4,5,6])
    • Khởi tạo bằng func of cùng với các giá trị khởi tạo.
    • Cho mỗi next event, Observable sẽ lần lượt emit ra các element được cung cấp.
    • Các giá trị cung cấp phải cùng kiểu dữ liệu: Cùng Int, String, …
    Sau khi phát ra hết các element, observable sẽ emit ra completed event và terminate.

    from:

    let observable = Observable.from([1,2,3])
    • Khi khởi tạo 1 Observable bằng func from, thì giá trị được khởi tạo mặc định phải thuộc kiểu Array.
    • Cho mỗi event next, Observable sẽ lần lượt emit ra các giá trị trong mảng.

    Sau khi emit hết các phần tử trong mảng, observable sẽ emit ra event completed và terminate.

    Ngoài of và from, thì còn các cách khởi tạo khác như just, never, empty.

    create:

    • Với các cách ở trên, thì observable sẽ tự động emit các event được cung cấp sẵn 1 cách lần lượt và tự emit 1 complete sau khi hoàn thành.
    • Bằng cách sử dụng hàm create để tạo 1 Observable, bạn có thể custom Observable theo cách riêng của ban để có thể emit ra completed hoặc error bất cứ khi nào bạn muốn
    let observable = Observable<String>.create({ observer in
        observer.onNext("Global")
        observer.onNext("Smart")
        observer.onCompleted()
        observer.onNext("Technology")
        return Disposables.create()
    })

    Kết quả được in ra: (Sau khi emit ra event complete thì observable sẽ bị terminate, do đó nó sẽ không emit ra "Technology" nữa.

    Subcribe:

    Chỉ copy đoạn code ở trên và run thì bạn sẽ không thấy có gì được print ra màn hình cả. Tại sao vậy?

    1 Observable chỉ có thể emit ra event khi nó được subcribe.

    Đoạn code ở trên, ta chưa subcribe Observable đó.Vậy làm thế nào để subcribe 1 Observable?

    subcribe event

    Để subcribe tới 1 Observable thì vô cùng đơn giản với hàm subcribe:

    let observable = Observable.of(1,2,3)
    observable.subscribe { (value) in
        print(value)
    }

    Để í phần Summary của hàm subcribe này: Đó là hàm có tác dụng subcribes 1 event. Vì vậy, các giá trị được print ra sẽ có cả kiểu của event được emit ra (next/complete/error).

    Kết quả print ra trên màn hình:

    Vậy nếu bạn muốn chỉ print ra giá trị của value mà không cần print ra kiểu event?

    subcribe element

    • Cách 1: Mỗi event sẽ có thuộc tính element để lấy ra giá trị đính kèm với event đó.
    observable.subscribe { (value) in
        if let element = value.element {
            print(element)
        }
    }
    • Cách 2: Sử dụng hàm subcribe:
    observable.subscribe(onNext: { (element) in
        print(element)
    })

    Theo như summary, hàm subcribe này sẽ subcribe đến element, vì vậy nó sẽ chỉ in ra giá trị của element.
    Cả 2 cách đều cho 1 kết quả như sau:

    Ngoài ra , với hàm trên, bạn có thể thực hiện các hành động khi observable emit ra event completed, error, … như sau:

    let observable = Observable<String>.create({ observer in
        observer.onNext("Global")
        observer.onNext("Smart")
        observer.onCompleted()
        observer.onNext("Technology")
        return Disposables.create()
    }).subscribe(onNext: { (element) in
        print(element)
    }, onCompleted: {
         print("Completed")
    })

    Kết luận:

    Observable là 1 thứ đơn giản nhưng vô cùng quan trọng trong RxSwift.

    Tham khảo: RxSwift – Reactive Programming with Swift v1.1