Function buidler
là tính năng được ưa thích nhất kể từ khi ra mắt cùngSwiftUI
trong versionSwift 5.1
.
Nó ngay lập tức là một phần quan trọng trong việc triển khaiSwiftUI
trong khi chưa đượcApple
phát triển hoàn chỉnh.Ở bài viết này chúng ta sẽ cùng tìm hiểu kỹ hơn về tính năng
function buidler
này để xem nó mang lại cho cho chúng ta những lợi ích thế nào trong việc triển khaicode
trongSwiftUI
.Lưu ý: Chúng ta cần nói rõ với nhau là
function buidler
được giới thiệu ở phiển bảnSwift 5.1
. Việc sử dụngFunction buidler
trong môi trường production tùy thuộc lớn vào project bạn đang phát triển đang hỗ trợ sử dụng versionSwift
nào. Hãy chắc chắn versionSwift
củaproject
bạn đang phát triển trước khi áp dụngfunction buidler
.
1: Setting:
- Cách tốt nhất với bản thân tôi khi tìm hiểu cách thức mà tính năng
Swift
hoạt động là thực hànhcode
ví dụ nào đó do đó chúng ta sẽ cùng cần một ví dụ với đầy đủ cácsetting
, chúng ta sẽ dùngSetting
như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">struct</span> <span class="token builtin">Setting</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token builtin">Value</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">Setting</span> <span class="token punctuation">{</span> <span class="token keyword">enum</span> <span class="token builtin">Value</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token function">bool</span><span class="token punctuation">(</span><span class="token builtin">Bool</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token function">int</span><span class="token punctuation">(</span><span class="token builtin">Int</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token function">string</span><span class="token punctuation">(</span><span class="token builtin">String</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Chúng ta sử dụng
associated type
cho các giá trị củaenum
để đảm bảo việc cho việc cácinstance setting
sẽ có đầy đủ cáctype
khác nhau.Thông qua việc tạo
group
chúng ta có thể tạo ra cácnested setting
như sau:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">let</span> settings <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">]</span> |
2: Sử dụng builder cho function:
- Điều cốt lõi của
Function builder
trongSwift
là giúp cho việcbuild
cáccontent
trongfunction
thành cácsingle value
. TrongSwiftUI
chúng ta sử dụng tính năng trên cho việctransform
cáccontent
của một hoặc nhiềucontainer
(HStack
hoặcVStack
) trong mộtview
bằng cách sử dụngtype(of:)
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">import</span> <span class="token builtin">SwiftUI</span> <span class="token keyword">let</span> stack <span class="token operator">=</span> <span class="token builtin">VStack</span> <span class="token punctuation">{</span> <span class="token function">Text</span><span class="token punctuation">(</span><span class="token string">"Hello"</span><span class="token punctuation">)</span> <span class="token function">Text</span><span class="token punctuation">(</span><span class="token string">"World"</span><span class="token punctuation">)</span> <span class="token function">Button</span><span class="token punctuation">(</span><span class="token string">"I'm a button"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// Prints 'VStack<TupleView<(Text, Text, Button<Text>)>>'</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token function">type</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> stack<span class="token punctuation">)</span><span class="token punctuation">)</span> |
SwiftUI
sử dụng cácfunction
khác nhau trong việcimplementations
nhưViewBuilder
vàSceneBuilder
. Nhưng việc chúng ta không thể tham khảosource code
cho cáctype
này nên chúng ta sẽbuild
cácFunction buidler
cho các setting trongAPI
này:Như tính năng property-wrappers-in-swift , một
function buidler
sẽ đảm nhiệm việcimplement
các loại type bình thường trongSwift
được giới thiệu với cú pháp@_functionBuilder
. Cácmethod
đặc biệt đã từng được dùng đểimplement
cáccase
làm việc củaFunction Builder
. Chúng ta tham khảo cách dùngbuildBlock
sau:
1 2 3 4 5 | @_functionBuilder <span class="token keyword">struct</span> <span class="token builtin">SettingsBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildBlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Cách
return type
trên trongfunction ([Setting])
phải chỉ định thêmtype
màbuilder
có thể sử dụng. Chúng ta sẽ chọn cáchimplement API
nhưglobal function
để sử dụng cácSettingsBuilder
cho bất kỳclosure
nào được truyền đến:
1 2 3 4 | <span class="token keyword">func</span> <span class="token function">makeSettings</span><span class="token punctuation">(</span>@<span class="token builtin">SettingsBuilder</span> <span class="token number">_</span> content<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token function">content</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- Với cách
code
trên chúng ta có thể gọimakeSettings
với mộttrailing closure
trống và nhận về mộtarray
trống:
1 2 | <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span><span class="token punctuation">}</span> |
API
mới của chúng ta vẫn chưa thực sự hữu dụng, nó mới chỉ cho chúng ta thấy một ít khả năng cũng như cách làm việc của nóFunction Builder
. Chúng ta sẽ tìm hiều kỹ hơn ở đầu mục tiếp theo:
3: Build các values:
- Để kích hoạt
SettingsBuilder
của chúng ta đểaccept
cácinput
thì việc của chúng ta cần làm là khai báo bổ sungbuildBlock
với cácargument
phù hợp vớiinput
cho kết quà mà chúng ta muốn nhận về. Chúng ta sẽimplement
mộtmethod
với list các valueSetting
vàreturn
về mộtarray
:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">SettingsBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildBlock</span><span class="token punctuation">(</span><span class="token number">_</span> settings<span class="token punctuation">:</span> <span class="token builtin">Setting</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> settings <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Với
buildBlock
mới vừa được khai báo, chúng ta sẽ cho phép fillmakeSettings
gọi đến cácSetting
value và cácfunction builder
sẽ tích hợp cho các value trongarray
vàreturn
:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- Chúng ta đã đạt được một sự cải tiến nhè nhẹ ở đây, bây giờ thì hãy quay về với
SwiftUI
và thêm vào cácfunction builder
với khả năng mạnh mẽ trong công việc định nghĩagroup
. Chúng ta sẽ cần thêm một typeSettingGroup
cóannotates
là@SettingsBuilder
để kết nối vớifunction buidler
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">struct</span> <span class="token builtin">SettingsGroup</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token keyword">var</span> settings<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token keyword">init</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token builtin">String</span><span class="token punctuation">,</span> @<span class="token builtin">SettingsBuilder</span> builder<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name <span class="token keyword">self</span><span class="token punctuation">.</span>settings <span class="token operator">=</span> <span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Cách triển khai trên cho phép chúng ta định nghĩa
group
giống cách chúng ta định nghĩa cácsetting
bằng cách kết nối mỗiSetting
vớiclosure
như sau:
1 2 3 4 5 | <span class="token function">SettingsGroup</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Nếu chúng ta cứ khăng khăng sử dụng
makeSettings closure
thì chúng ta sẽ bị báo lỗi vì cácmethod function builder
sẽ đang đợi rất nhiều giá trịSetting
vàSettingGroup
mới của chúng ta là mộttype
hoàn toàn khác.Để xử lý
error
trên chúng ta cần thêm cácprototol
để có thể chia sẻ giữaSetting
vàSettingGroup
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">protocol</span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">Setting</span><span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">SettingsGroup</span><span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> name<span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Công việc tiếp theo cần làm là
modify
cácfunction buidler
củabuildBlock
đểaccept
cácSettingsConvertible
được khởi tạo hơn là sử dụng giá trị màSetting
được trả về thông qua map:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">SettingsBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildBlock</span><span class="token punctuation">(</span><span class="token number">_</span> values<span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> values<span class="token punctuation">.</span>flatMap <span class="token punctuation">{</span> $<span class="token number">0</span><span class="token punctuation">.</span><span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Bây giờ chúng ta đã có đầy đủ phương tiện để sử dụng đầy đủ tính năng của
SwiftUI
hỗ trợ bằng cách thiết laapk cácgroup
như sau:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">SettingsGroup</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
4: Các điều kiện sử dụng Function Builder:
- Chúng ta có thể thêm vào các
conditional
để hỗ trợ việc sử dụngFunction Builder
. Bản thânSwift
đã hỗ trợ tất cả các loạiconditional
chúng ta cần sử dụng, tuy nhiên trong trường hợp vớiSettingsBuilder
hiện tại đangimplement
chúng ta sẽ gặp phải error nếu chúng ta cố gắng làm như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">let</span> shouldShowExperimental<span class="token punctuation">:</span> <span class="token builtin">Bool</span> <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// Compiler error: Closure containing control flow statement</span> <span class="token comment">// cannot be used with function builder 'SettingsBuilder'.</span> <span class="token keyword">if</span> shouldShowExperimental <span class="token punctuation">{</span> <span class="token function">SettingsGroup</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Đoạn
code
trên cho chúng ta thấy cáchexecuted
của cácfunction builder
vớiannotated
không được thực hiện giống với cách thông dụng mà chúng ta thường sử dụng vì các tiến trình xử lý cần được định nghĩa rõ ràng bỏibuilder
bao gồm cảconditional
nhưif statement
:Chúng ta cần thêm các
statement
đểsort
và xử lý vấn đề trên. Chúng ta có thêm mộtmethod
được giới thiệu trong API làbuidlIf
. Tác dụng của nó làmap
mỗiif statement
:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment">// Here we extend Array to make it conform to our SettingsConvertible</span> <span class="token comment">// protocol, in order to be able to return an empty array from our</span> <span class="token comment">// 'buildIf' implementation in case a nil value was passed:</span> <span class="token keyword">extension</span> <span class="token builtin">Array</span><span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span> <span class="token keyword">where</span> <span class="token builtin">Element</span> <span class="token operator">==</span> <span class="token builtin">Setting</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">SettingsBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildIf</span><span class="token punctuation">(</span><span class="token number">_</span> value<span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> value <span class="token operator">?</span><span class="token operator">?</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
if statement
ở trên bây giờ đã có thể hoạt động chính xác với mong đợi của chúng ta nhưng chúng ta vẫn cần thêm cácif/else
để có thể bổ sungmethod buildEither
với các cácargument
phù hợp với cácif/else statement
:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">extension</span> <span class="token builtin">SettingsBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildEither</span><span class="token punctuation">(</span><span class="token builtin">first</span><span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> <span class="token builtin">first</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">buildEither</span><span class="token punctuation">(</span>second<span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> second <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Chúng ta thêm vào
else
choif statement
đầu tiên của chúng ta từ trước nên chúng ta có ví dụ cho việc cácuser
sẽrequest
cácsetting
mà trước đó chưa được hiển thị:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">if</span> shouldShowExperimental <span class="token punctuation">{</span> <span class="token function">SettingsGroup</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Request experimental access"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Cho đến tận
Swift 5.3
, cácmethod buildEither
mới được hỗ trợswift statement
để sử dụng cho việcbuild context
mà không cần thêm cácbuild method
.Chúng ta sẽ cố cải tiến đoạn code trên thêm một chút cho biến
shouldShowExperimental
trongenum
bằng cách hỗ trợ việcaccess
nhiều level khác nhau. Đơn giản là chúng ta có thể chuyển đổi qua lại trongenum
vớimakeSettings closure
và trình biên dịch sẽ tự động chuyển đếnmethod buildEither
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token keyword">enum</span> <span class="token builtin">UserAccessLevel</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> restricted <span class="token keyword">case</span> normal <span class="token keyword">case</span> experimental <span class="token punctuation">}</span> <span class="token keyword">let</span> accesssLevel<span class="token punctuation">:</span> <span class="token builtin">UserAccessLevel</span> <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">let</span> settings <span class="token operator">=</span> makeSettings <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Offline mode"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Search page size"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">switch</span> accesssLevel <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span>restricted<span class="token punctuation">:</span> <span class="token builtin">Setting</span><span class="token punctuation">.</span><span class="token function">Empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span>normal<span class="token punctuation">:</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Request experimental access"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span>experimental<span class="token punctuation">:</span> <span class="token function">SettingsGroup</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Experimental"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Default name"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">"Untitled"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">Setting</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"Fluid animations"</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Bổ sung thêm một chú ý là
type Setting.Empty
với mỗiswitch statement
trongcase
có thể sẽ cần sử dụng thêm.restricted
break keywork
với cácfunction builder
sử dụngswitch statement
. Như cách sử dụngEmptyView
trongSwiftUI
, cácSetting API
mới đã có thêmSetting.Empty
cho trường hợp này:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">Setting</span> <span class="token punctuation">{</span> <span class="token keyword">struct</span> <span class="token builtin">Empty</span><span class="token punctuation">:</span> <span class="token builtin">SettingsConvertible</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">asSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token builtin">Setting</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |