- vừa được xem lúc

Code ngắn gọn hơn với OptionSet trong Swift

0 0 26

Người đăng: Long Vu Thanh

Theo Viblo Asia

Nếu bạn muốn biết cách xử lý với Bitmasks trong Swift hay là bạn đã từng nghe đến OptionSet chưa? Bài viết này sẽ giúp bạn hiểu hơn về điều đó ?

1. OptionSet là gì?

Về cơ bản, OptionSet là một protocol, khi confirm nó chúng ta có thể làm việc với bit mask. Nó là một đại diện cho việc gán mỗi bit tương ứng với một option. Hãy cùng tìm hiểu thêm nhé.

2. Cách implement OptionSet.

Dưới đây là một ví dụ cơ bản về sử dụng OptionSet:

struct MyStruct: OptionSet { let rawValue: Int static let firstOption = MyStruct(rawValue: 1 << 0) static let secondOption = MyStruct(rawValue: 1 << 1) static let thirdOption = MyStruct(rawValue: 1 << 2)
}

Giờ hãy giải thích về đoạn code trên nhé. Việc confirm OptionSet protocol yêu cầu cần khai báo rawValue, nó không nhất thiết phải thuộc loại Int mà là bất kì loại nào của FixedWidthInteger như Int8 hay Int16. Tiếp theo, bạn cũng cần khai báo static các option. Đó là tất cả những gì bạn cần làm với OptionSet ?

Chắc hẳn bạn sẽ thắc mắc vì sao lại cần dùng static<< ?

Về mặt logic, các option cần được khai báo static vì bạn sẽ truy cập trực tiếp vào nó mà không cần khởi tạo đối tương. Tiếp theo, option được khai báo như một instance của struct với việc gán rawValue với mã nhị phân vì thế cần sử dụng toán tử <<

Ví dụ:

let one = 0b0001 // 1
let shiftedZero = one << 2 // 4 (0b0100)
let twentyOne = 0b0010101 // 21
let shiftedTewntyOne = twentyOne << 2 // 84 (1010100)

Ở ví dụ trên, chúng ta chỉ chuyển dịch các bit thành 1 và 21

static let firstOption = MyStruct(rawValue: 1 << 0)
static let secondOption = MyStruct(rawValue: 1 << 1)
static let thirdOption = MyStruct(rawValue: 1 << 2)

nó cũng giống như:

static let firstOption = MyStruct(rawValue: 1)
static let secondOption = MyStruct(rawValue: 2)
static let thirdOption = MyStruct(rawValue: 4)

Vậy tại sao lại cần dùng << có thể thuận tiện hơn khi đảm bảo rằng bạn không phá vỡ quy tắc của công thức đếm nhị phân (1,2,4,8,16,..)

Tại sao lại cần sử dụng OptionSet?

Bạn có thể đơn giản coi nó như một option kết hợp với một biến. Hãy cùng xem ví dụ dưới đây:

Ví dụ:

Hãy thử xem chúng ta có một ứng dụng cho phép người dùng chọn vật nuôi yêu thích. Với yêu cầu đó chắc hẳn bạn sẽ nghĩ ngay tới enum.

enum Pet { case pussycat, puppy, hamster, chameleon
}

và dễ dàng sử dụng:

let favortiePet: Pet = .puppy

Tuy nhiên, chúng ta đã biết rằng mọi thứ thay đổi rất nhiều, yêu cầu của ứng dụng đã thay đổi là người dùng có thể lựa chọn nhiều vật nuôi yêu thích. Chúng ta sẽ cần làm thế này:

let favortiePets: [Pet] = [.pussycat, .puppy]

Hiện tại thì có vẻ hợp lí, tuy nhiên trong một số trường hợp điều này không được tốt cho lắm. Chẳng hạn, nếu giá trị này cần được gửi đến một phía máy chủ thì sao? nó sẽ được gửi dưới dạng danh sách?

Bây giờ chúng ta hãy thử sử dụng OptionSet để thấy sự khác biệt:

struct Pet: OptionSet { let rawValue: UInt8 static let pussycat = Pet(rawValue: 1 << 0) static let puppy = Pet(rawValue: 1 << 1) static let hamster = Pet(rawValue: 1 << 2) static let chameleon = Pet(rawValue: 1 << 3)
}
let singlePet: Pet = .puppy
let multiplePets: Pet = [.puppy, .pussycat]

Chú ý rằng multiplePets có type là Pet và không phải [Pet]. Nếu bạn thử in rawValue bạn sẽ thấy rằng singlePet là 2 (1<<1) và multiplePets là 3 (1<<1 + 1<<0)

Bằng cách thực hiện theo phương pháp sử dụng OptionSet, bạn có thể đại diện cho nhiều tùy chọn bằng cách chỉ sử dụng một UInt8 duy nhất:

Thú cưng yêu thích là pussycat: rawValue = 1 Vật nuôi yêu thích là hamster và chameleon: rawValue = 12 (4 + 8) Vật nuôi yêu thích là tất cả: rawValue = 15 (1 + 2 + 4 + 8)

Ngoài ra còn một tính năng thú vị của OptionSet là các thao tác liên quan đến operation ví dụ:

let options1: Pet = [.pussycat, .puppy]
let options2: Pet = [.puppy, .hamster, .chameleon]
let intersection = options1.intersection(options2)
print(intersection) // Pet(rawValue: 2) ? puppy
let union = options1.union(options2)
print(union) // Pet(rawValue: 15) ? pussycat, puppy, hamster & chameleon
let subtracting = options1.subtracting(options2)
print(subtracting) // Pet(rawValue: 1) ? pussycat
let contains = options1.contains(.hamster)
print(contains) // false

Lưu ý:

OptionSet hoạt động dự trên bit masks, bạn có thể thấy nó là một lựa chọn tốt để lưu trữ danh sách hữu hạn các option dưới dạng một biến duy nhất. Tuy nhiên, hãy lưu ý để sử dụng nó một cách thông minh! và nó không phải là Collection

Nguồn tham khảo:

https://medium.com/@ahmadfayyas/swift-more-elegant-code-optionset-205e4866b4aa

Bình luận

Bài viết tương tự

- vừa được xem lúc

Swift: Tạo custom phép toán tử (Operator) của riêng bạn!

Swift cho phép bạn tạo các toán tử có thể tùy chỉnh của riêng bạn. Điều này đặc biệt hữu ích khi bạn xử lý các loại dữ liệu của riêng mình. Operator Types in Swift. Có năm loại toán tử chính trong Swift.

0 0 45

- vừa được xem lúc

Chương 6 Protocol oriented programming.

Cuốn sách này là về lập trình hướng protocol. Khi Apple thông báo swift 2 ở WWDC 2015.

0 0 28

- vừa được xem lúc

Ví dụ về UIActivityViewController

Trên iOS, UIActivityViewController cung cấp giao diện thống nhất để người dùng chia sẻ và thực hiện các hành động trên văn bản, hình ảnh, URL và các mục khác trong ứng dụng. let string = "Hello, world!". let url = URL(string: "https://nshipster.com").

0 0 45

- vừa được xem lúc

Quản lý self và cancellable trong Combine.

. . Công việc quản lý bộ nhớ memory management thường trở nên phức tạp khi chúng ta thực hiện các tác vụ bất đồng bộ asynchronous vì chúng ta thường phải lưu giữ một số object nằm ngoài scope mà object được define trong khi vẫn phải đảm bảo được việc giải phóng object đó được thực hiện đúng quy trìn

0 0 28

- vừa được xem lúc

[SWIFT] Sử dụng Dependency Injection với Storyboards

1. Lời mở đầu:.

0 0 30

- vừa được xem lúc

Tạo hiệu ứng Story của Instagram bằng SwiftUI

. Có lẽ chúng ta đã quá quen thuộc với Story ở trên Instagram hoặc trên Facebook. Nó là những video và hình ảnh được liên kết với nhau như một thư viện hình ảnh để kể câu truyện nào đó.

0 0 38