dnrops.gitlink.net/posts/swift/swiftui_extension.html

797 lines
53 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="coal" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>SwiftUI extensions - Andrew&#x27;s Blog</title>
<!-- Custom HTML head -->
<meta name="description" content="Andrew Ryan&#x27;s Blog">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../src/style/custom.css">
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "coal" : "coal";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('coal')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item affix "><a href="../../index.html">Andrew's Blog</a></li><li class="chapter-item "><a href="../../posts/linux/linux.html"><strong aria-hidden="true">1.</strong> linux</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/linux/install_linux.html"><strong aria-hidden="true">1.1.</strong> install linux</a></li><li class="chapter-item "><a href="../../posts/linux/bash_profile.html"><strong aria-hidden="true">1.2.</strong> bash profile</a></li><li class="chapter-item "><a href="../../posts/linux/command_list.html"><strong aria-hidden="true">1.3.</strong> command list</a></li><li class="chapter-item "><a href="../../posts/linux/git_guide.html"><strong aria-hidden="true">1.4.</strong> git guide</a></li><li class="chapter-item "><a href="../../posts/linux/tar.html"><strong aria-hidden="true">1.5.</strong> tar</a></li><li class="chapter-item "><a href="../../posts/linux/run_x86_elf_in_x64_setup.html"><strong aria-hidden="true">1.6.</strong> run x86 elf in x64 setup</a></li></ol></li><li class="chapter-item "><a href="../../posts/mac/mac.html"><strong aria-hidden="true">2.</strong> mac</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/mac/macos_profiles.html"><strong aria-hidden="true">2.1.</strong> macos profiles</a></li></ol></li><li class="chapter-item expanded "><a href="../../posts/swift/swift.html"><strong aria-hidden="true">3.</strong> swift</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/swift/learn_swift.html"><strong aria-hidden="true">3.1.</strong> learn swift basics</a></li><li class="chapter-item "><a href="../../posts/swift/swift_extensions.html"><strong aria-hidden="true">3.2.</strong> Swift extensions</a></li><li class="chapter-item expanded "><a href="../../posts/swift/swiftui_extension.html" class="active"><strong aria-hidden="true">3.3.</strong> SwiftUI extensions</a></li><li class="chapter-item "><a href="../../posts/swift/install_swift.html"><strong aria-hidden="true">3.4.</strong> install swift</a></li><li class="chapter-item "><a href="../../posts/swift/task_planner.html"><strong aria-hidden="true">3.5.</strong> implment task panner app with SwiftUI</a></li><li class="chapter-item "><a href="../../posts/swift/swift_cheat_sheet.html"><strong aria-hidden="true">3.6.</strong> Swift Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/swift/yinci_url.html"><strong aria-hidden="true">3.7.</strong> Personal privacy protocol</a></li><li class="chapter-item "><a href="../../posts/swift/swift_regular_exressions.html"><strong aria-hidden="true">3.8.</strong> Swift regular exressions</a></li><li class="chapter-item "><a href="../../posts/ios/how_to_create_beautiful_ios_charts_in_swift.html"><strong aria-hidden="true">3.9.</strong> How to Create Beautiful iOS Charts in鑱絊wift</a></li><li class="chapter-item "><a href="../../posts/swift/swiftui_source_code.html"><strong aria-hidden="true">3.10.</strong> SwiftUI source code</a></li><li class="chapter-item "><a href="../../posts/swift/use_swift_fetch_iciba_api.html"><strong aria-hidden="true">3.11.</strong> use swift fetch iciba API</a></li></ol></li><li class="chapter-item "><a href="../../posts/ios/ios.html"><strong aria-hidden="true">4.</strong> ios</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ios/cocaposd_setup_and_install_for_ios_project.html"><strong aria-hidden="true">4.1.</strong> cocaposd setup and install for ios project</a></li><li class="chapter-item "><a href="../../posts/ios/swiftui_show_gif_image.html"><strong aria-hidden="true">4.2.</strong> SwiftUI show gif image</a></li><li class="chapter-item "><a href="../../posts/ios/implement_task_planner_app.html"><strong aria-hidden="true">4.3.</strong> implement Task planner App</a></li></ol></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c.html"><strong aria-hidden="true">5.</strong> objective_c</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/objective_c/objective_c_cheat_sheet.html"><strong aria-hidden="true">5.1.</strong> Objective-C Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c_for_absolute_beginners_read_note.html"><strong aria-hidden="true">5.2.</strong> Objective-C Note</a></li></ol></li><li class="chapter-item "><a href="../../posts/dart/dart.html"><strong aria-hidden="true">6.</strong> dart</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/dart/flutter.html"><strong aria-hidden="true">6.1.</strong> Flutter Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/dart/dart_cheat_sheet.html"><strong aria-hidden="true">6.2.</strong> Dart Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/flutter/flutter_dev_test.html"><strong aria-hidden="true">6.3.</strong> Flutter dev test</a></li></ol></li><li class="chapter-item "><a href="../../posts/rust/rust.html"><strong aria-hidden="true">7.</strong> rust</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/rust/offline_use_rust.html"><strong aria-hidden="true">7.1.</strong> Offline use rust</a></li><li class="chapter-item "><a href="../../posts/rust/rust_grammer.html"><strong aria-hidden="true">7.2.</strong> rust grammar</a></li><li class="chapter-item "><a href="../../posts/rust/pase_string_and_decimal_conversion.html"><strong aria-hidden="true">7.3.</strong> pase string and decimal conversion</a></li><li class="chapter-item "><a href="../../posts/rust/parse_types.html"><strong aria-hidden="true">7.4.</strong> rust types</a></li><li class="chapter-item "><a href="../../posts/rust/rust_life_cycle.html"><strong aria-hidden="true">7.5.</strong> Rust life cycle</a></li><li class="chapter-item "><a href="../../posts/rust/rust_generic.html"><strong aria-hidden="true">7.6.</strong> rust generics</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implment_matrix.html"><strong aria-hidden="true">7.7.</strong> Rust implement matrix</a></li><li class="chapter-item "><a href="../../posts/rust/rust_sort.html"><strong aria-hidden="true">7.8.</strong> Rust implement sort algorithms</a></li><li class="chapter-item "><a href="../../posts/rust/implement_aes_encryption.html"><strong aria-hidden="true">7.9.</strong> Rust implement AEC encryption and decryption</a></li><li class="chapter-item "><a href="../../posts/rust/implement_trie_data_structure.html"><strong aria-hidden="true">7.10.</strong> implement trie data structure</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_tree.html"><strong aria-hidden="true">7.11.</strong> implement tree data_structure</a></li><li class="chapter-item "><a href="../../posts/rust/list_dir.html"><strong aria-hidden="true">7.12.</strong> list dir</a></li><li class="chapter-item "><a href="../../posts/rust/fast_way_to_implment_object_trait.html"><strong aria-hidden="true">7.13.</strong> fast way to implment object trait</a></li><li class="chapter-item "><a href="../../posts/rust/compress_rust_binary_size.html"><strong aria-hidden="true">7.14.</strong> compress rust binary size</a></li><li class="chapter-item "><a href="../../posts/rust/implment_file_upload_backend.html"><strong aria-hidden="true">7.15.</strong> impliment file upload</a></li><li class="chapter-item "><a href="../../posts/rust/this_is_add_post_cli_implementation_in_rust.html"><strong aria-hidden="true">7.16.</strong> this is add_post cli implementation in rust</a></li><li class="chapter-item "><a href="../../posts/rust/use_rust_implment_a_copyclipbord_cli.html"><strong aria-hidden="true">7.17.</strong> Use rust implment a copyclipbord CLI</a></li><li class="chapter-item "><a href="../../posts/rust/sqlite_database_add_delete_update_show_in_rust.html"><strong aria-hidden="true">7.18.</strong> sqlite database add delete update show in rust</a></li><li class="chapter-item "><a href="../../posts/rust/implementing_tokio_joinhandle_for_wasm.html"><strong aria-hidden="true">7.19.</strong> Implementing tokio JoinHandle for wasm</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_a_crate_for_encode_and_decode_brainfuck_and_ook.html"><strong aria-hidden="true">7.20.</strong> rust implement a crate for encode and decode brainfuck and ook</a></li><li class="chapter-item "><a href="../../posts/rust/slint_builtin_elements.html"><strong aria-hidden="true">7.21.</strong> Slint Builtin Elements</a></li><li class="chapter-item "><a href="../../posts/rust/corporate_network_install_rust_on_windows.html"><strong aria-hidden="true">7.22.</strong> Corporate network install Rust on windows</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_file_how_to_judge_static_link_or_dynamic_link_in_macos.html"><strong aria-hidden="true">7.23.</strong> rust binary file how to judge static link or dynamic link in Macos</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_include_dir_and_get_contents.html"><strong aria-hidden="true">7.24.</strong> rust binary include dir and get contents</a></li><li class="chapter-item "><a href="../../posts/rust/rust_logger_non-block.html"><strong aria-hidden="true">7.25.</strong> rust logger non-block</a></li><li class="chapter-item "><a href="../../posts/rust/rust_connect_sql_server_database.html"><strong aria-hidden="true">7.26.</strong> rust connect sql server database</a></li><li class="chapter-item "><a href="../../posts/rust/rust_websocket_implment.html"><strong aria-hidden="true">7.27.</strong> rust websocket implment</a></li></ol></li><li class="chapter-item "><a href="../../posts/java/java.html"><strong aria-hidden="true">8.</strong> java</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/java/java_grammar.html"><strong aria-hidden="true">8.1.</strong> java grammar and codewar</a></li><li class="chapter-item "><a href="../../posts/java/run_jar.html"><strong aria-hidden="true">8.2.</strong> java run .jar</a></li><li class="chapter-item "><a href="../../posts/java/java_pomxml_add_defaultgoal_to_build.html"><strong aria-hidden="true">8.3.</strong> Java pomxml add defaultGoal to build</a></li><li class="chapter-item "><a href="../../posts/java/java_set_mvn_mirror.html"><strong aria-hidden="true">8.4.</strong> Java set mvn mirror</a></li></ol></li><li class="chapter-item "><a href="../../posts/python/python.html"><strong aria-hidden="true">9.</strong> python</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/python/convert_pesn.html"><strong aria-hidden="true">9.1.</strong> convert pesn</a></li><li class="chapter-item "><a href="../../posts/python/find_remove_dir.html"><strong aria-hidden="true">9.2.</strong> find and remove dir</a></li><li class="chapter-item "><a href="../../posts/python/timing_message.html"><strong aria-hidden="true">9.3.</strong> wechat send message</a></li><li class="chapter-item "><a href="../../posts/python/use_python_openpyxl_package_read_and_edit_excel_files.html"><strong aria-hidden="true">9.4.</strong> Use python openpyxl package read and edit excel files</a></li></ol></li><li class="chapter-item "><a href="../../posts/go/go.html"><strong aria-hidden="true">10.</strong> go</a></li><li class="chapter-item "><a href="../../posts/js/js.html"><strong aria-hidden="true">11.</strong> js</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/js/js_tutorial.html"><strong aria-hidden="true">11.1.</strong> js tutorial</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_map.html"><strong aria-hidden="true">11.2.</strong> ja map</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_math.html"><strong aria-hidden="true">11.3.</strong> js math</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_object.html"><strong aria-hidden="true">11.4.</strong> js object</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_set.html"><strong aria-hidden="true">11.5.</strong> js set</a></li><li class="chapter-item "><a href="../../posts/js/single_thread_and_asynchronous.html"><strong aria-hidden="true">11.6.</strong> single thread and asynchronous</a></li><li class="chapter-item "><a href="../../posts/js/this.html"><strong aria-hidden="true">11.7.</strong> js this</a></li><li class="chapter-item "><a href="../../posts/js/js_implment_aes.html"><strong aria-hidden="true">11.8.</strong> js implment aes</a></li><li class="chapter-item "><a href="../../posts/js/getting_started_with_ajax.html"><strong aria-hidden="true">11.9.</strong> getting started with ajax</a></li><li class="chapter-item "><a href="../../posts/js/BinarySearchTree.html"><strong aria-hidden="true">11.10.</strong> binary search tree</a></li><li class="chapter-item "><a href="../../posts/js/goole_zx.html"><strong aria-hidden="true">11.11.</strong> goole zx</a></li><li class="chapter-item "><a href="../../posts/js/es6.html"><strong aria-hidden="true">11.12.</strong> es6</a></li></ol></li><li class="chapter-item "><a href="../../posts/ruby/ruby.html"><strong aria-hidden="true">12.</strong> ruby</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ruby/rails_setup_env.html"><strong aria-hidden="true">12.1.</strong> ruby on rails setup environment</a></li><li class="chapter-item "><a href="../../posts/ruby/learn_ruby.html"><strong aria-hidden="true">12.2.</strong> learn ruby</a></li><li class="chapter-item "><a href="../../posts/ruby/ruby_note.html"><strong aria-hidden="true">12.3.</strong> Ruby Note</a></li><li class="chapter-item "><a href="../../posts/ruby/setup_ruby_for_ctf.html"><strong aria-hidden="true">12.4.</strong> Setup ruby for CTF</a></li></ol></li><li class="chapter-item "><a href="../../posts/react/react.html"><strong aria-hidden="true">13.</strong> react</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/react/react_life_cycle.html"><strong aria-hidden="true">13.1.</strong> react life cycle</a></li><li class="chapter-item "><a href="../../posts/react/react_router.html"><strong aria-hidden="true">13.2.</strong> react router</a></li><li class="chapter-item "><a href="../../posts/react/react_this.html"><strong aria-hidden="true">13.3.</strong> react this</a></li><li class="chapter-item "><a href="../../posts/react/react_interviw.html"><strong aria-hidden="true">13.4.</strong> react interview</a></li><li class="chapter-item "><a href="../../posts/react/important_react_interview.html"><strong aria-hidden="true">13.5.</strong> important react interview</a></li><li class="chapter-item "><a href="../../posts/react/react_quick_reference.html"><strong aria-hidden="true">13.6.</strong> react quick reference</a></li><li class="chapter-item "><a href="../../posts/react/redux_quick_reference.html"><strong aria-hidden="true">13.7.</strong> redux quick reference</a></li></ol></li><li class="chapter-item "><a href="../../posts/vue/vue.html"><strong aria-hidden="true">14.</strong> vue</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/vue/vue_ajax.html"><strong aria-hidden="true">14.1.</strong> vue ajax</a></li></ol></li><li class="chapter-item "><a href="../../posts/angular/angular.html"><strong aria-hidden="true">15.</strong> angular</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/angular/controller_communication.html"><strong aria-hidden="true">15.1.</strong> controller communication</a></li><li class="chapter-item "><a href="../../posts/angular/creating_custom_directives.html"><strong aria-hidden="true">15.2.</strong> creating custom directives</a></li><li class="chapter-item "><a href="../../posts/angular/directive_notes.html"><strong aria-hidden="true">15.3.</strong> directive notes</a></li><li class="chapter-item "><a href="../../posts/angular/directive_communication.html"><strong aria-hidden="true">15.4.</strong> directive communication</a></li><li class="chapter-item "><a href="../../posts/angular/post_params.html"><strong aria-hidden="true">15.5.</strong> post params</a></li><li class="chapter-item "><a href="../../posts/angular/read_json_angular.html"><strong aria-hidden="true">15.6.</strong> read json angular</a></li><li class="chapter-item "><a href="../../posts/angular/same_route_reload.html"><strong aria-hidden="true">15.7.</strong> same route reload</a></li></ol></li><li class="chapter-item "><a href="../../posts/css/css.html"><strong aria-hidden="true">16.</strong> css</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/css/use_css_media.html"><strong aria-hidden="true">16.1.</strong> use css media</a></li></ol></li><li class="chapter-item "><a href="../../posts/php/php.html"><strong aria-hidden="true">17.</strong> php</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/php/for_php_string_implment_some_extemtion_functions.html"><strong aria-hidden="true">17.1.</strong> for php string implment some extemtion functions</a></li><li class="chapter-item "><a href="../../posts/php/php_cheatsheet.html"><strong aria-hidden="true">17.2.</strong> PHP cheatsheet</a></li></ol></li><li class="chapter-item "><a href="../../posts/leetcode/leetcode.html"><strong aria-hidden="true">18.</strong> leetcode</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/leetcode/rust_leetcode.html"><strong aria-hidden="true">18.1.</strong> rust leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_codewar.html"><strong aria-hidden="true">18.2.</strong> rust codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/swift_codewar.html"><strong aria-hidden="true">18.3.</strong> swift codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/js_leetcode.html"><strong aria-hidden="true">18.4.</strong> js leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/java_leetcode.html"><strong aria-hidden="true">18.5.</strong> java leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_huawei.html"><strong aria-hidden="true">18.6.</strong> huawei test</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_utils.html"><strong aria-hidden="true">18.7.</strong> rust common functions</a></li><li class="chapter-item "><a href="../../posts/leetcode/olympiad_training.html"><strong aria-hidden="true">18.8.</strong> Computer olympiad training</a></li></ol></li><li class="chapter-item "><a href="../../posts/ctf/CTF.html"><strong aria-hidden="true">19.</strong> ctf</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ctf/CTF_Note.html"><strong aria-hidden="true">19.1.</strong> CTF Note</a></li><li class="chapter-item "><a href="../../posts/ctf/0.1_Web.html"><strong aria-hidden="true">19.2.</strong> Web</a></li><li class="chapter-item "><a href="../../posts/ctf/4.1_Misc.html"><strong aria-hidden="true">19.3.</strong> Misc</a></li><li class="chapter-item "><a href="../../posts/ctf/3.2_PWN_note.html"><strong aria-hidden="true">19.4.</strong> PWN</a></li><li class="chapter-item "><a href="../../posts/ctf/3.1_Crypto.html"><strong aria-hidden="true">19.5.</strong> Crypto</a></li><li class="chapter-item "><a href="../../posts/ctf/3.4_RSA_note.html"><strong aria-hidden="true">19.6.</strong> Rsa attack</a></li><li class="chapter-item "><a href="../../posts/ctf/3.5_Base64.html"><strong aria-hidden="true">19.7.</strong> Base64</a></li><li class="chapter-item "><a href="../../posts/ctf/0.0_SQL Injection Cheatsheet.html"><strong aria-hidden="true">19.8.</strong> SQL Injection Cheatsheet</a></li><li class="chapter-item "><a href="../../posts/ctf/1.1_SQL_injection.html"><strong aria-hidden="true">19.9.</strong> SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.2_SQL_injection_UNION_attacks.html"><strong aria-hidden="true">19.10.</strong> SQL Injection UNION attacks</a></li><li class="chapter-item "><a href="../../posts/ctf/1.3_Blind SQL injection.html"><strong aria-hidden="true">19.11.</strong> Blind SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.4_Code Injection.html"><strong aria-hidden="true">19.12.</strong> Code Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.5_SSRF.html"><strong aria-hidden="true">19.13.</strong> SSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.6_OS command injection.html"><strong aria-hidden="true">19.14.</strong> OS command injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.7_Local file inclusion.html"><strong aria-hidden="true">19.15.</strong> Local file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.8_Remote file inclusion.html"><strong aria-hidden="true">19.16.</strong> Remote file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.9_CSRFm.html"><strong aria-hidden="true">19.17.</strong> CSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.10_NoSQL injection.html"><strong aria-hidden="true">19.18.</strong> NoSQL injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.11_JSON injection.html"><strong aria-hidden="true">19.19.</strong> JSON injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.12_CTF_Web_SQL_Note.html"><strong aria-hidden="true">19.20.</strong> CTF Web SQL Note</a></li><li class="chapter-item "><a href="../../posts/ctf/2.1_XXE.html"><strong aria-hidden="true">19.21.</strong> XXE</a></li><li class="chapter-item "><a href="../../posts/ctf/2.2_XSS.html"><strong aria-hidden="true">19.22.</strong> XSS</a></li><li class="chapter-item "><a href="../../posts/ctf/2.3_Upload File.html"><strong aria-hidden="true">19.23.</strong> Upload File</a></li><li class="chapter-item "><a href="../../posts/ctf/2.4_serialize_unserialize.html"><strong aria-hidden="true">19.24.</strong> serialize unserialize</a></li><li class="chapter-item "><a href="../../posts/ctf/2.5_Race condition.html"><strong aria-hidden="true">19.25.</strong> Race condition</a></li><li class="chapter-item "><a href="../../posts/ctf/3.2_PWN_note.html"><strong aria-hidden="true">19.26.</strong> PWN_note</a></li><li class="chapter-item "><a href="../../posts/ctf/3.3_pwn HCTF2016 brop.html"><strong aria-hidden="true">19.27.</strong> pwn HCTF2016 brop</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_patch_defense_skill.html"><strong aria-hidden="true">19.28.</strong> PWN Patch defense skill</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_stack_overflow.html"><strong aria-hidden="true">19.29.</strong> PWN stack overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_heap_overflow.html"><strong aria-hidden="true">19.30.</strong> PWN heap overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_format_string_vulnerability.html"><strong aria-hidden="true">19.31.</strong> PWN Format String Vulnerability</a></li><li class="chapter-item "><a href="../../posts/ctf/kali_linux_tutorials.html"><strong aria-hidden="true">19.32.</strong> Kali linux tutorials</a></li><li class="chapter-item "><a href="../../posts/ctf/google_dorks_2023_lists.html"><strong aria-hidden="true">19.33.</strong> Google Dorks 2023 Lists</a></li><li class="chapter-item "><a href="../../posts/ctf/dvwa_writeup.html"><strong aria-hidden="true">19.34.</strong> DVWA WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/bwapp_writeup.html"><strong aria-hidden="true">19.35.</strong> bWAPP WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/sqlilabs_writeup.html"><strong aria-hidden="true">19.36.</strong> sqlilabs WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/ctf_train_at_hangzhou.html"><strong aria-hidden="true">19.37.</strong> ctf train at hangzhou</a></li><li class="chapter-item "><a href="../../posts/ctf/ctf_common_mindmap_list.html"><strong aria-hidden="true">19.38.</strong> ctf common mindmap list</a></li><li class="chapter-item "><a href="../../posts/ctf/error_based_sql_injection.html"><strong aria-hidden="true">19.39.</strong> Error Based SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/urlfinder_tutorial.html"><strong aria-hidden="true">19.40.</strong> URLFinder Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/observer_ward_tutorial.html"><strong aria-hidden="true">19.41.</strong> observer_ward Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/mysql_udf_.html"><strong aria-hidden="true">19.42.</strong> MySQL UDF 提权</a></li><li class="chapter-item "><a href="../../posts/ctf/nuclei__tutorial.html"><strong aria-hidden="true">19.43.</strong> Nuclei Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/2024_ctf_solution_thinking.html"><strong aria-hidden="true">19.44.</strong> 2024 ctf solution thinking</a></li><li class="chapter-item "><a href="../../posts/ctf/man_che_si_te_bian_ma.html"><strong aria-hidden="true">19.45.</strong> 曼彻斯特编码</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Andrew&#x27;s Blog</h1>
<div class="right-buttons">
<a href="https://gitlink.org.cn/dnrops/dnrops.gitlink.net.git" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="swiftui-extensions"><a class="header" href="#swiftui-extensions">SwiftUI extensions</a></h1>
<h2 id="for-swiftui-view"><a class="header" href="#for-swiftui-view">for SwiftUI View</a></h2>
<pre><code class="language-swift">import SwiftUI
import Combine
extension View {
//readSize
func readSize(onChange: @escaping (CGSize) -&gt; Void) -&gt; some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: ReadSizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(ReadSizePreferenceKey.self, perform: onChange)
}
}
//ReadSizePreferenceKey
private struct ReadSizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -&gt; CGSize) {}
}
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
/// toImage
func toImage() -&gt; UIImage? {
let controller = UIHostingController(rootView: self)
let view = controller.view
view?.backgroundColor = .clear
let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
controller.view.bounds = CGRect(origin: .zero, size: size)
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
return image
}
/// Type casting to AnyView
///
/// myView.eraseToAnyView()
///
/// - Returns: A view as AnyView
@inlinable func eraseToAnyView() -&gt; AnyView {
AnyView(self)
}
/// Encapsulate view in navigation view
///
/// myView.embedInNavigation()
///
/// - Returns: A view encapsulate in navigation view
@available(watchOS, unavailable)
@inlinable func embedInNavigation() -&gt; some View {
NavigationView { self }
}
/// Positions the view within an invisible frame with the specified size.
///
/// myView.frame(size: CGSize(width: 100, height: 100))
///
/// - Returns: A view with fixed dimensions of width and height
@inlinable func frame(size: CGSize) -&gt; some View {
frame(width: size.width, height: size.height)
}
/// Calls a block each time that view is reloaded
///
/// content.onReload(perform: {
/// print("onReload")
/// })
///
/// - Returns: The same view but calling the block asynchronously when is reloaded
@inlinable func onReload(perform: @escaping () -&gt; Void) -&gt; some View {
DispatchQueue.main.async {
perform()
}
return self
}
}
// MARK: Building
public extension View {
/// Apply changes to the view if the condition is true
///
/// myView
/// .if(index == state.currentIndex, then: {
/// $0.background(Color.red)
/// })
///
/// - Parameters:
/// - condition: an boolean to control the condition
/// - then: callback to apply the changes when the condition is true
/// - Returns: some View
@inlinable func `if`&lt;Content: View&gt;(
_ conditional: Bool,
then: (Self) -&gt; Content
) -&gt; TupleView&lt;(Self?, Content?)&gt; {
if conditional {
return TupleView((nil, then(self)))
}
return TupleView((self, nil))
}
/// Apply some changes to the view in place of the condition
///
/// myView
/// .if(index == state.currentIndex, then: {
/// $0.background(Color.red)
/// }, else: {
/// $0.background(Color.yellow)
/// })
///
/// - Parameters:
/// - condition: an boolean to control the condition
/// - then: callback to apply the changes when the condition is true
/// - else: callback to apply the changes when the condition is false
/// - Returns: some View
@inlinable func `if`&lt;A: View, B: View&gt;(
_ conditional: Bool,
then: (Self) -&gt; A,
`else`: (Self) -&gt; B
) -&gt; TupleView&lt;(A?, B?)&gt; {
if conditional {
return TupleView((then(self), nil))
}
return TupleView((nil, `else`(self)))
}
}
// MARK: Modifiers
public extension View {
/// Set one modifier conditionally.
///
/// myView.conditionalModifier(myCondition, myViewModifier)
///
/// - Parameters:
/// - condition: an boolean to control the condition
/// - modifier: modifier to apply
/// - Returns: some View
@inlinable func conditionalModifier&lt;M: ViewModifier&gt;(
_ condition: Bool,
_ modifier: M
) -&gt; TupleView&lt;(Self?, ModifiedContent&lt;Self, M&gt;?)&gt; {
if condition {
return TupleView((nil, self.modifier(modifier)))
}
return TupleView((self, nil))
}
/// Set one modifier or another conditionally.
///
/// myView.conditionalModifier(myCondition, firstViewModifier, secondViewModifier)
///
/// - Parameters:
/// - condition: an boolean to control the condition
/// - trueModifier: modifier to apply when the condition is true
/// - falseModifier: modifier to apply when the condition is false
/// - Returns: some View
@inlinable func conditionalModifier&lt;M: ViewModifier&gt;(
_ condition: Bool,
_ trueModifier: M,
_ falseModifier: M
) -&gt; TupleView&lt;(ModifiedContent&lt;Self, M&gt;?, ModifiedContent&lt;Self, M&gt;?)&gt; {
if condition {
return TupleView((self.modifier(trueModifier), nil))
}
return TupleView((nil, self.modifier(falseModifier)))
}
}
// MARK: Animations
public extension View {
/// Animate an action with an animation on appear.
///
/// myView.animateOnAppear(using: .easeInOut) { self.scale = 0.5 }
///
/// - Parameters:
/// - animation: animation to be applied
/// - action: action to be animated
/// - Returns: some View
@inlinable func animateOnAppear(using animation: Animation = .easeInOut,
action: @escaping () -&gt; Void) -&gt; some View {
return onAppear {
withAnimation(animation) {
action()
}
}
}
/// Animate an action with an animation on disappear.
///
/// myView.animateOnDisappear(using: .easeInOut) { self.scale = 0.5 }
///
/// - Parameters:
/// - animation: animation to be applied
/// - action: action to be animated
/// - Returns: some View
@inlinable func animateOnDisappear(using animation: Animation = .easeInOut,
action: @escaping () -&gt; Void) -&gt; some View {
return onDisappear {
withAnimation(animation) {
action()
}
}
}
}
// MARK: Combine
public extension View {
/// Bind publisher to state
///
/// The following example uses this method to implement an async image view.
/// ```
/// struct AsyncImage: View {
/// @State private var image: UIImage
/// private let source: AnyPublisher&lt;UIImage, Never&gt;
/// private let animation: Animation?
///
/// init(
/// source: AnyPublisher&lt;UIImage, Never&gt;,
/// placeholder: UIImage,
/// animation: Animation? = nil
/// ) {
/// self.source = source
/// self.animation = animation
/// self._image = State(initialValue:placeholder)
/// }
///
/// var body: some View {
/// return Image(uiImage: image)
/// .resizable()
/// .bind(source, to: $image.animation(animation))
/// }
/// }
/// ```
///
/// - Parameters:
/// - publisher: publisher to observe when a value is received
/// - state: state to assign the new value
/// - Returns: some View
@inlinable func bind&lt;P: Publisher, Value&gt;(
_ publisher: P,
to state: Binding&lt;Value&gt;
) -&gt; some View where P.Failure == Never, P.Output == Value {
return onReceive(publisher) { value in
state.wrappedValue = value
}
}
}
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
/// Tracks the size available for the view
///
/// myView.sizeTrackable($size)
///
/// - Parameter size: This binding will receive the size updates
@inlinable func sizeTrackable(_ size: Binding&lt;CGSize&gt;) -&gt; some View {
self.modifier(SizeViewModifier(size: size))
}
}
</code></pre>
<h2 id="for-swiftui-lineargradient"><a class="header" href="#for-swiftui-lineargradient">for SwiftUI LinearGradient</a></h2>
<pre><code class="language-swift">import SwiftUI
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension LinearGradient {
/// Create a gradient directly from colors
///
/// let myGradient = LinearGradient(Color.red, Color.blue)
///
/// - Parameters:
/// - colors: array of colors
/// - startPoint: unit point where gradient starts
/// - endPoint: unit point where gradient starts
/// - Returns: A new linear gradient
@inlinable init(_ colors: Color..., startPoint: UnitPoint = .topLeading, endPoint: UnitPoint = .bottomTrailing) {
self.init(gradient: Gradient(colors: colors), startPoint: startPoint, endPoint: endPoint)
}
}
</code></pre>
<h2 id="for-swiftui-image"><a class="header" href="#for-swiftui-image">for SwiftUI Image</a></h2>
<pre><code class="language-swift">import SwiftUI
#if canImport(UIKit)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public extension Image {
/// Create a image with default one
///
/// let image = Image("photo", defaultImage: "empty-photo")
///
/// - Parameters:
/// - name: Image name
/// - defaultImage: Default image name
/// - Returns: A new image
@inlinable init(_ name: String, defaultImage: String) {
if let img = UIImage(named: name) {
self.init(uiImage: img)
} else {
self.init(defaultImage)
}
}
/// Create a image with default one
///
/// let image = Image("photo", defaultSystemImage: "bandage.fill")
///
/// - Parameters:
/// - name: Image name
/// - defaultSystemImage: Default system image name
/// - Returns: A new image
@available(OSX 10.15, *)
@inlinable init(_ name: String, defaultSystemImage: String) {
if let img = UIImage(named: name) {
self.init(uiImage: img)
} else {
self.init(systemName: defaultSystemImage)
}
}
}
#endif
#if canImport(AppKit)
@available(OSX 10.15, *)
public extension Image {
/// Create a image with default one
///
/// let image = Image("photo", defaultImage: "empty-photo")
///
/// - Parameters:
/// - name: Image name
/// - defaultImage: Default image name
/// - Returns: A new image
@inlinable init(_ name: String, defaultImage: String) {
if let img = NSImage(named: name) {
self.init(nsImage: img)
} else {
self.init(defaultImage)
}
}
}
#endif
</code></pre>
<h2 id="for-swiftui-color"><a class="header" href="#for-swiftui-color">for SwiftUI Color</a></h2>
<pre><code class="language-swift">import SwiftUI
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension Color {
/// Create a color from hex string
/// It supports hex string of rgb and rgba with the # character as optional
/// Examples: #AABBCC, AABBCC, #AABBCCFF or AABBCCFF.
///
/// let myGradient = Color(hex: "#FFFFFF")
///
/// - Parameters:
/// - hex: Hex color string
/// - Returns: New color from the hex value
@inlinable init?(hex: String) {
let hexColor: String
if hex.hasPrefix("#") {
let start = hex.index(hex.startIndex, offsetBy: 1)
hexColor = String(hex[start...])
} else {
hexColor = hex
}
let count = hexColor.count
guard count == 6 || count == 8 else {
return nil
}
let scanner = Scanner(string: hexColor)
var hexNumber: UInt64 = 0
guard scanner.scanHexInt64(&amp;hexNumber) else {
return nil
}
let r, g, b, a: Double
if count == 6 { //rgb
r = Double((hexNumber &amp; 0x00ff0000) &gt;&gt; 16)
g = Double((hexNumber &amp; 0x0000ff00) &gt;&gt; 8)
b = Double(hexNumber &amp; 0x000000ff)
a = 255
} else { //rgba
r = Double((hexNumber &amp; 0xff000000) &gt;&gt; 24)
g = Double((hexNumber &amp; 0x00ff0000) &gt;&gt; 16)
b = Double((hexNumber &amp; 0x0000ff00) &gt;&gt; 8)
a = Double(hexNumber &amp; 0x000000ff)
}
self.init(.sRGB, red: r / 255, green: g / 255, blue: b / 255, opacity: a / 255)
}
}
</code></pre>
<h2 id="swiftui-modifiers"><a class="header" href="#swiftui-modifiers">SwiftUI Modifiers</a></h2>
<pre><code class="language-swift">import SwiftUI
/// This modifier wraps a view into a `GeometryReader` and tracks the available space.
///
/// @State var size: CGSize = .zero
///
/// myView.modifier(SizeViewModifier(size: $size))
///
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public struct SizeViewModifier: ViewModifier {
@Binding private(set) var size: CGSize
/// Create a size view modifier from a CGSize binding
///
/// myView.modifier(SizeViewModifier(size: $size))
///
/// - Parameters:
/// - size: CGSize binding
/// - Returns: A new modifier
public init(size: Binding&lt;CGSize&gt;) {
self._size = size
}
public func body(content: Content) -&gt; some View {
GeometryReader { proxy in
content
.frame(size: proxy.size)
.onReload(perform: {
self.size = proxy.size
})
}
}
}
</code></pre>
<h2 id="swiftui-utils-functions"><a class="header" href="#swiftui-utils-functions">swiftUI Utils functions</a></h2>
<pre><code class="language-swift">import SwiftUI
/// It is an utility that adds back a way to use the if let.
///
/// ifLet(myImage, then: {
/// $0.resizable()
/// })
///
/// - Parameters:
/// - value: optional value to verify
/// - then: callback to create a view with the value is not nil
/// - Returns: The built view
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@inlinable public func ifLet&lt;T, ThenOut: View&gt;(_ value: T?, then: (T) -&gt; ThenOut) -&gt; some View {
ViewBuilder.buildIf(value.map { then($0) })
}
/// It is an utility that adds back a way to use the if let with an else option
///
/// ifLet(myImage, then: {
/// $0.resizable()
/// }, else: {
/// Text("Hello")
/// })
///
/// - Parameters:
/// - value: optional value to verify
/// - then: callback to create a view with the value is not nil
/// - else: callback to create a view with the value is nil
/// - Returns: The built view
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@inlinable public func ifLet&lt;T, ThenOut: View, ElseOut: View&gt;(
_ value: T?,
then: (T) -&gt; ThenOut,
`else`: () -&gt; ElseOut) -&gt; some View {
value.map { ViewBuilder.buildEither(first: then($0)) } ??
ViewBuilder.buildEither(second: `else`())
}
/// It is an utility that adds back a way to use the if let for collections checking if it is empty.
///
/// ifLet(myText, empty: false, then: {
/// Text($0)
/// })
///
/// - Parameters:
/// - value: optional value to verify
/// - empty: condition to check if string is valid when is empty.
/// - then: callback to create a view with the value is not nil
/// - Returns: The built view
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@inlinable public func ifLet&lt;T, ThenOut: View&gt;(
_ value: T?,
empty: Bool = false,
then: (T) -&gt; ThenOut
) -&gt; some View where T : Collection {
let value = !empty &amp;&amp; value.isNilOrEmpty ? nil : value
return ViewBuilder.buildIf(value.map { then($0) })
}
/// It is an utility that adds back a way to use the if let with an else option
///
/// ifLet(myText, empty: false, then: {
/// $0
/// }, else: {
/// Text("Hello")
/// })
///
/// - Parameters:
/// - value: optional value to verify
/// - empty: condition to check if string is valid when is empty.
/// - then: callback to create a view with the value is not nil
/// - else: callback to create a view with the value is nil
/// - Returns: The built view
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@inlinable public func ifLet&lt;T, ThenOut: View, ElseOut: View&gt;(
_ value: T?,
empty: Bool = false,
then: (T) -&gt; ThenOut,
`else`: () -&gt; ElseOut
) -&gt; some View where T : Collection {
let value = !empty &amp;&amp; value.isNilOrEmpty ? nil : value
return value.map { ViewBuilder.buildEither(first: then($0)) } ??
ViewBuilder.buildEither(second: `else`())
}
</code></pre>
<h2 id="for-swiftui-userdefault"><a class="header" href="#for-swiftui-userdefault">for SwiftUI UserDefault</a></h2>
<pre><code class="language-swift">import Foundation
/// A type that adds an interface to use the users defaults with default types
///
/// Example:
/// ```
/// @UserDefault(key: "nameKey", defaultValue: "Root") var name: String
/// ```
/// Adding the attribute @UserDefault the property works reading and writing from user's defaults
///
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct UserDefault&lt;T&gt; {
private let key: String
private let defaultValue: T
/// Initialize the key and the default value.
public init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
public var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
</code></pre>
<h2 id="for-swiftui-userdefaultenum"><a class="header" href="#for-swiftui-userdefaultenum">for SwiftUI UserDefaultEnum</a></h2>
<pre><code class="language-swift">import Foundation
/// A type that adds an interface to use the users defaults with raw representable types where the raw value is of type string
///
/// Example:
/// ```
/// enum Beverage: String, CaseIterable {
/// case coffee, tea, juice
/// }
///
/// @UserDefaultEnum(key: "beverageKey", defaultValue: .coffee) var beverage: Beverage
/// ```
/// Adding the attribute @UserDefaultEnum the property works reading and writing from user's defaults
///
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct UserDefaultEnum&lt;T: RawRepresentable&gt; where T.RawValue == String {
private let key: String
private let defaultValue: T
/// Initialize the key and the default value.
public init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
public var wrappedValue: T {
get {
if let string = UserDefaults.standard.string(forKey: key) {
return T(rawValue: string) ?? defaultValue
}
return defaultValue
}
set {
UserDefaults.standard.set(newValue.rawValue, forKey: key)
}
}
}
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../posts/swift/swift_extensions.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../posts/swift/install_swift.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../posts/swift/swift_extensions.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../posts/swift/install_swift.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_line_numbers = true;
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../../ace.js"></script>
<script src="../../editor.js"></script>
<script src="../../mode-rust.js"></script>
<script src="../../theme-dawn.js"></script>
<script src="../../theme-tomorrow_night.js"></script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
<script src="../../src/js/custom.js"></script>
</div>
</body>
</html>