Option Set 및 Sorcery를 사용하여 손쉬운 SwiftUI 보기 바인딩
토글이 많은 SwiftUI 보기를 본 적이 있습니까?
struct LotsOfStateView: View {
//1
@State var showBackground = false
//2
@State var showBorder = false
//3
@State var reduceMotionEnabled = false
//4
@State var largeFont = false
//5
@State var receiveEmailNotifications = false
var body: some View {
VStack {
Toggle(isOn: $showBackground) {
Text(LocalizedStringKey("Show Background"))
}
Toggle(isOn: $showBorder) {
Text(LocalizedStringKey("Show Border"))
}
Toggle(isOn: $reduceMotionEnabled) {
Text(LocalizedStringKey("Reduce Motion Enabled"))
}
Toggle(isOn: $largeFont) {
Text(LocalizedStringKey("Large Font"))
}
Toggle(isOn: $receiveEmailNotifications) {
Text(LocalizedStringKey("Receive Notifications"))
}
}
.padding()
.font(.system(size: 22, weight: .light, design: .rounded))
}
}
이러한 토글을 처리하는 것은 꽤 간단한 작업이지만 더 많이 추가할수록 번거로울 수 있습니다.
Bool 값의 양을 줄이는 기술은 하나의 저장 단위로 압축하는 것입니다. 본질적으로 그것들을 일련의 0과 1로 변환할 수 있습니다. 익숙한 것 같나요?
There are only 10 types of people in the world – those who understand binary, and those who don’t.
따라서 위의 @State를 보다 관리하기 쉬운 것으로 변환하려면 Swift의
OptionSet
를 사용할 수 있습니다. 그것들은 enums
와 매우 유사합니다.이전에 미리 알림을 설정하셨을 것입니다. 예를 들어 알림 빈도(월요일, 수요일 및 토요일)를 설정하는 경우. 기본적으로 3개의 값 집합을 생성합니다.
원하는 값의 조합을 생성할 수 있다는 이 기본 아이디어는 우리가 보기에 있는 상용구 상태의 양을 제거하는 데 완벽합니다.
위의 @State를 OptionSet으로 변환하려면 다음과 같이 할 수 있습니다.
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
static let showBackground = Self(rawValue: 1 << 0)
static let showBorder = Self(rawValue: 1 << 1)
static let reduceMotionEnabled = Self(rawValue: 1 << 2)
static let largeFont = Self(rawValue: 1 << 3)
static let receiveEmailNotifications = Self(rawValue: 1 << 4)
}
그런 다음 우리의 관점에서 하나를 위해 모든 @State를 제거할 수 있습니다.
@State var viewOptions = Options.none
OptionSet의 rawValue를 보면 UInt입니다. 본질적으로 값의 합집합을 하나의 단일 저장 값으로 저장하고 있습니다. (101001 계열, 온/오프)
이것이 귀하의 보기와 같습니다.
struct LessStateVariablesView: View {
@State var viewOptions = Options.none
var body: some View {
ZStack {
if $viewOptions.bindValue(.showBackground) {
Color.red.edgesIgnoringSafeArea(.all)
}
VStack {
Toggle(isOn: $viewOptions.bind(.showBackground)) {
Text(LocalizedStringKey("Show Background"))
}
Toggle(isOn: $viewOptions.bind(.showBorder)) {
Text(LocalizedStringKey("Show Border"))
}
Toggle(isOn: $viewOptions.bind(.reduceMotionEnabled)) {
Text(LocalizedStringKey("Reduce Motion Enabled"))
}
Toggle(isOn: $viewOptions.bind(.largeFont)) {
Text(LocalizedStringKey("Large Font"))
}
Toggle(isOn: $viewOptions.bind(.receiveEmailNotifications)) {
Text(LocalizedStringKey("Receive Notifications"))
}
}
.padding()
.font(.system(size: 22, weight: .light, design: .rounded))
}
}
}
보시다시피 이전 @State를 모두 이동하고 OptionSet으로 캡슐화했습니다. 동작은 정확히 동일하지만 5개의 bool을 갖는 대신 1을 가지며 모든 true 및 false는 1개의 단일 UInt로 저장됩니다.
OptionSet을 바인딩으로 변환
이제 옵션이 있으므로 SwiftUI 보기에서 옵션과 상호 작용하는 방법이 필요합니다. 예를 들어 토글을 사용하려면 Binding
이 필요합니다.
A property wrapper type that can read and write a value owned by a source of truth.
바인딩은 일반 값Value
이 있는 구조체이므로 새 OptionSet과 상호 작용하기 위해 확장을 작성할 수 있습니다.
extension Binding where Value: OptionSet, Value == Value.Element {
func bindedValue(_ options: Value) -> Bool {
return wrappedValue.contains(options)
}
func bind(
_ options: Value,
animate: Bool = false
) -> Binding<Bool> {
return .init { () -> Bool in
self.wrappedValue.contains(options)
} set: { newValue in
let body = {
if newValue {
self.wrappedValue.insert(options)
} else {
self.wrappedValue.remove(options)
}
}
guard animate else {
body()
return
}
withAnimation {
body()
}
}
}
}
이렇게 함으로써 이제 SwiftUI 보기에 연결할 수 있습니다.
이제 bindedValue
에 액세스하여 Bool 표현을 꺼내고 Toggle에 전달하여 값을 업데이트할 수 있는 bind
도 있습니다. 변경 사항을 애니메이션화하기 위한 편리한 옵션animate
도 있습니다.
보일러 플레이트 제거(구조용 소스)
OptionSet을 작성하는 것은 매우 사소하지만 각 항목에 필요한 구문과 올바른 항목rawValue
을 잊어버리는 경우가 많습니다.
OptionSet을 매우 간단하고 쉽게 만들기 위해 Sourcery와 함께 사용할 수 있는 템플릿 파일Stencil
을 만들었습니다.
Sourcery is a code generator for Swift language, built on top of Apple's own SwiftSyntax. It extends the language abstractions to allow you to generate boilerplate code automatically.
Sourcery
지금 우리가 할 수 있는 일은 귀하의 사례로 열거형을 만들고 귀하가 OptionsBinding
를 준수하는지 확인하는 것입니다.
protocol OptionsBinding {}
enum MyEnum: OptionsBinding {
case showBackground
case showBorder
case reduceMotionEnabled
case largeFont
case receiveEmailNotifications
}
그런 다음 Sourcery는 해당 열거형을 확장하고 이에 상응하는 OptionSet을 추가합니다.
extension MyEnum {
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
static let showBackground = Self(rawValue: 1 << 0)
static let showBorder = Self(rawValue: 1 << 1)
static let reduceMotionEnabled = Self(rawValue: 1 << 2)
static let largeFont = Self(rawValue: 1 << 3)
static let receiveEmailNotifications = Self(rawValue: 1 << 4)
}
}
이제 필요할 때마다 MyEnum.Options를 자유롭게 사용할 수 있습니다.
이것이 일부 사람들이 뷰에서 Bool 상용구를 줄이는 데 도움이 되고 좋은 열거형을 사용하여 옵션을 쉽게 추론할 수 있기를 바랍니다.
스텐실 템플릿
{% for type in types.enums where type.cases.count > 0 and type.based.OptionsBinding or type|annotated:"OptionsBinding" %}
extension {{ type.name }} {
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
{% for i in 0...type.cases.count %}
{% if not forloop.last %}
static let {{type.cases[i].name}} = Self(rawValue: 1 << {{i}})
{% endif %}
{% endfor %}
}
}
{% endfor %}
extension Binding where Value: OptionSet, Value == Value.Element {
func bindValue(_ options: Value) -> Bool {
return wrappedValue.contains(options)
}
func bind(
_ options: Value,
animate: Bool = false
) -> Binding<Bool> {
return .init { () -> Bool in
self.wrappedValue.contains(options)
} set: { newValue in
let body = {
if newValue {
self.wrappedValue.insert(options)
} else {
self.wrappedValue.remove(options)
}
}
guard animate else {
body()
return
}
withAnimation {
body()
}
}
}
}
참조 / 유용한 링크
Source Code
Custom OptionSet
OptionSet
Sourcery
Reference
이 문제에 관하여(Option Set 및 Sorcery를 사용하여 손쉬운 SwiftUI 보기 바인딩), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/vibrazy/easy-swiftui-view-bindings-using-optionset-and-sourcery-4edb
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
A property wrapper type that can read and write a value owned by a source of truth.
extension Binding where Value: OptionSet, Value == Value.Element {
func bindedValue(_ options: Value) -> Bool {
return wrappedValue.contains(options)
}
func bind(
_ options: Value,
animate: Bool = false
) -> Binding<Bool> {
return .init { () -> Bool in
self.wrappedValue.contains(options)
} set: { newValue in
let body = {
if newValue {
self.wrappedValue.insert(options)
} else {
self.wrappedValue.remove(options)
}
}
guard animate else {
body()
return
}
withAnimation {
body()
}
}
}
}
OptionSet을 작성하는 것은 매우 사소하지만 각 항목에 필요한 구문과 올바른 항목
rawValue
을 잊어버리는 경우가 많습니다.OptionSet을 매우 간단하고 쉽게 만들기 위해 Sourcery와 함께 사용할 수 있는 템플릿 파일
Stencil
을 만들었습니다.Sourcery is a code generator for Swift language, built on top of Apple's own SwiftSyntax. It extends the language abstractions to allow you to generate boilerplate code automatically.
Sourcery
지금 우리가 할 수 있는 일은 귀하의 사례로 열거형을 만들고 귀하가
OptionsBinding
를 준수하는지 확인하는 것입니다.protocol OptionsBinding {}
enum MyEnum: OptionsBinding {
case showBackground
case showBorder
case reduceMotionEnabled
case largeFont
case receiveEmailNotifications
}
그런 다음 Sourcery는 해당 열거형을 확장하고 이에 상응하는 OptionSet을 추가합니다.
extension MyEnum {
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
static let showBackground = Self(rawValue: 1 << 0)
static let showBorder = Self(rawValue: 1 << 1)
static let reduceMotionEnabled = Self(rawValue: 1 << 2)
static let largeFont = Self(rawValue: 1 << 3)
static let receiveEmailNotifications = Self(rawValue: 1 << 4)
}
}
이제 필요할 때마다 MyEnum.Options를 자유롭게 사용할 수 있습니다.
이것이 일부 사람들이 뷰에서 Bool 상용구를 줄이는 데 도움이 되고 좋은 열거형을 사용하여 옵션을 쉽게 추론할 수 있기를 바랍니다.
스텐실 템플릿
{% for type in types.enums where type.cases.count > 0 and type.based.OptionsBinding or type|annotated:"OptionsBinding" %}
extension {{ type.name }} {
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
{% for i in 0...type.cases.count %}
{% if not forloop.last %}
static let {{type.cases[i].name}} = Self(rawValue: 1 << {{i}})
{% endif %}
{% endfor %}
}
}
{% endfor %}
extension Binding where Value: OptionSet, Value == Value.Element {
func bindValue(_ options: Value) -> Bool {
return wrappedValue.contains(options)
}
func bind(
_ options: Value,
animate: Bool = false
) -> Binding<Bool> {
return .init { () -> Bool in
self.wrappedValue.contains(options)
} set: { newValue in
let body = {
if newValue {
self.wrappedValue.insert(options)
} else {
self.wrappedValue.remove(options)
}
}
guard animate else {
body()
return
}
withAnimation {
body()
}
}
}
}
참조 / 유용한 링크
Source Code
Custom OptionSet
OptionSet
Sourcery
Reference
이 문제에 관하여(Option Set 및 Sorcery를 사용하여 손쉬운 SwiftUI 보기 바인딩), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/vibrazy/easy-swiftui-view-bindings-using-optionset-and-sourcery-4edb
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
{% for type in types.enums where type.cases.count > 0 and type.based.OptionsBinding or type|annotated:"OptionsBinding" %}
extension {{ type.name }} {
struct Options: OptionSet {
var rawValue: UInt
static let none = Self([])
{% for i in 0...type.cases.count %}
{% if not forloop.last %}
static let {{type.cases[i].name}} = Self(rawValue: 1 << {{i}})
{% endif %}
{% endfor %}
}
}
{% endfor %}
extension Binding where Value: OptionSet, Value == Value.Element {
func bindValue(_ options: Value) -> Bool {
return wrappedValue.contains(options)
}
func bind(
_ options: Value,
animate: Bool = false
) -> Binding<Bool> {
return .init { () -> Bool in
self.wrappedValue.contains(options)
} set: { newValue in
let body = {
if newValue {
self.wrappedValue.insert(options)
} else {
self.wrappedValue.remove(options)
}
}
guard animate else {
body()
return
}
withAnimation {
body()
}
}
}
}
Source Code
Custom OptionSet
OptionSet
Sourcery
Reference
이 문제에 관하여(Option Set 및 Sorcery를 사용하여 손쉬운 SwiftUI 보기 바인딩), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/vibrazy/easy-swiftui-view-bindings-using-optionset-and-sourcery-4edb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)