<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    
    <title>GitHub Swift Weekly Trending Repositories</title>
    <description>Weekly Trending Repositories of Swift on GitHub</description>
    
    <pubDate>Mon, 10 Aug 2026 07:38:09 GMT</pubDate>
    <link>https://mshibanami.github.io/GitHubTrendingRSS</link>
    
    <item>
      <title>Lakr233/vphone-cli</title>
      <link>https://github.com/Lakr233/vphone-cli</link>
      <description>&lt;div align=&quot;right&quot;&gt;
 &lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/docs/README_ko.md&quot;&gt;🇰🇷한국어&lt;/a&gt;&lt;/strong&gt; | 
 &lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/docs/README_ja.md&quot;&gt;🇯🇵日本語&lt;/a&gt;&lt;/strong&gt; | 
 &lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/docs/README_zh.md&quot;&gt;🇨🇳中文&lt;/a&gt;&lt;/strong&gt; | 
 &lt;strong&gt;🇬🇧English&lt;/strong&gt;
&lt;/div&gt; 
&lt;h1&gt;vphone-cli&lt;/h1&gt; 
&lt;p&gt;Boot a virtual iPhone via Apple&#39;s Virtualization.framework using PCC research VM infrastructure.&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/docs/demo.jpeg&quot; alt=&quot;poc&quot; /&gt;&lt;/p&gt; 
&lt;h2&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Host:&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Apple Silicon&lt;/li&gt; 
 &lt;li&gt;macOS 15+ (Sequoia)&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/#sipamfi-relaxation&quot;&gt;SIP/AMFI relaxation to allow private PV=3 entitlements with unsigned-binary&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Dependencies:&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install python@3.13 aria2 wget gnu-tar openssl@3 ldid-procursus sshpass keystone cmake libusb ipsw zstd
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Install&lt;/h2&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install zqxwce/tap/vphone-cli
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Build&lt;/h2&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone --recurse-submodules https://github.com/Lakr233/vphone-cli.git

./scripts/setup_tools.sh      # install deps, build toolchain submodules, create the Python venv
./scripts/build.sh            # build + sign vphone-cli, bundle the .app, cross-compile vphoned

cd .build/vphone-cli.app/Contents/MacOS/
vphone-cli --help
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Quick Start&lt;/h2&gt; 
&lt;p&gt;One command creates a VM end-to-end (download → patch → DFU restore → CFW install → first boot):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vphone-cli vm create myphone -V jb        # -V / --variant

vphone-cli vm launch myphone
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Commands&lt;/h2&gt; 
&lt;p&gt;&lt;code&gt;vphone-cli vm create&lt;/code&gt; runs the whole pipeline; the individual steps below let you drive it manually or re-run one stage.&lt;/p&gt; 
&lt;h3&gt;Manage&lt;/h3&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vphone-cli vm list                         # list VMs (--json for scripting)
vphone-cli vm info myphone                  # show one VM
vphone-cli vm new myphone                   # create an empty bundle (cpu/mem/disk options)
vphone-cli vm config myphone --cpu 8 --memory 8192
vphone-cli vm clone myphone myphone-2       # fast APFS clone, fresh device identity
vphone-cli vm export myphone --out myphone.tar.xz   # xz -9; skips restore dir + staging files
vphone-cli vm import --in myphone.tar.xz --name restored
vphone-cli vm rename myphone iphone16
vphone-cli vm delete iphone16
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Build a VM manually (what &lt;code&gt;vm create&lt;/code&gt; automates)&lt;/h3&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vphone-cli vm new myphone                              # 1. empty bundle
vphone-cli fw prepare myphone --iphone-version 26.1     # 2. download + merge IPSWs
vphone-cli fw patch myphone --variant jb                # 3. patch the boot chain

vphone-cli vm launch myphone --dfu &amp;amp;                    # 4. boot into DFU (background)
vphone-cli restore myphone --get-shsh                   #    fetch SHSH
vphone-cli restore myphone                              #    DFU restore
vphone-cli vm stop myphone                              #    stop the DFU boot

vphone-cli cfw install myphone --variant jb             # 5. install CFW (host-mount; asks for sudo)
vphone-cli vm launch myphone                            # 6. first boot
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Update to a newer iOS by pointing &lt;code&gt;fw prepare&lt;/code&gt; at an IPSW: &lt;code&gt;--iphone-source /path/to.ipsw --cloudos-source /path/to.ipsw&lt;/code&gt;.&lt;/p&gt; 
&lt;h2&gt;Firmware Variants&lt;/h2&gt; 
&lt;p&gt;Five patch variants with increasing security bypass — pass one to &lt;code&gt;--variant&lt;/code&gt;:&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Variant&lt;/th&gt; 
   &lt;th&gt;Boot Chain&lt;/th&gt; 
   &lt;th&gt;CFW&lt;/th&gt; 
   &lt;th&gt;Notes&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;less&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;4 patches&lt;/td&gt; 
   &lt;td&gt;2 phases&lt;/td&gt; 
   &lt;td&gt;Patchless — keeps iOS mitigations enabled&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;regular&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;42 patches&lt;/td&gt; 
   &lt;td&gt;10 phases&lt;/td&gt; 
   &lt;td&gt;AMFI/SSV/Img4/TXM bypass&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;dev&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;53 patches&lt;/td&gt; 
   &lt;td&gt;12 phases&lt;/td&gt; 
   &lt;td&gt;+ TXM entitlement/debug bypass&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;jb&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;113 patches&lt;/td&gt; 
   &lt;td&gt;14 phases&lt;/td&gt; 
   &lt;td&gt;+ full jailbreak (Sileo, TrollStore auto-install on first boot)&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;141 patches&lt;/td&gt; 
   &lt;td&gt;18 phases&lt;/td&gt; 
   &lt;td&gt;JB superset + anti-VM-detection research patches&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/research/0_binary_patch_comparison.md&quot;&gt;&lt;code&gt;research/0_binary_patch_comparison.md&lt;/code&gt;&lt;/a&gt; for the per-component breakdown.&lt;/p&gt; 
&lt;h2&gt;Running &amp;amp; Connecting&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;SSH (jailbreak):&lt;/strong&gt; &lt;code&gt;ssh -p 22222 mobile@&amp;lt;vm-ip&amp;gt;&lt;/code&gt; (password &lt;code&gt;alpine&lt;/code&gt;)&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;SSH (regular/dev):&lt;/strong&gt; &lt;code&gt;ssh -p 22222 root@&amp;lt;vm-ip&amp;gt;&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;VNC:&lt;/strong&gt; &lt;code&gt;vnc://&amp;lt;vm-ip&amp;gt;:5901&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Locations&lt;/h2&gt; 
&lt;p&gt;Everything vphone-cli creates lives under &lt;code&gt;~/.vphone/&lt;/code&gt; — kept outside the repo and the &lt;code&gt;.app&lt;/code&gt; so the signed bundle stays portable:&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Path&lt;/th&gt; 
   &lt;th&gt;Contents&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;~/.vphone/VMs/&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;VM bundles — one directory per VM. This is the library; override with &lt;code&gt;$VPHONE_LIBRARY_ROOT&lt;/code&gt;.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;~/.vphone/ipsws/&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Downloaded iPhone + cloudOS IPSWs, cached and reused across VMs.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;~/.vphone/tools/&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Cached APFS seal-volume artifacts (&lt;code&gt;apfs_sealvolume_&amp;lt;version&amp;gt;&lt;/code&gt;) fetched during &lt;code&gt;fw prepare&lt;/code&gt;.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;~/.vphone/debs/&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Cached &lt;code&gt;.deb&lt;/code&gt; packages the &lt;code&gt;jb&lt;/code&gt;/&lt;code&gt;exp&lt;/code&gt; CFW install lays into the guest (Sileo, apt, …).&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;~/.vphone/venv/&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Auto-provisioned Python environment (see &lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/#python-runtime&quot;&gt;Python runtime&lt;/a&gt;; override with &lt;code&gt;$VPHONE_VENV_DIR&lt;/code&gt;).&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h2&gt;SIP/AMFI Relaxation&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Option A — fully disable SIP, then disable AMFI via boot-arg (most permissive).&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;In Recovery (long-press power → Terminal):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;csrutil disable
csrutil allow-research-guests enable
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Then reboot into macOS and set the AMFI boot-arg (needs SIP fully off to take effect):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo nvram boot-args=&quot;amfi_get_out_of_my_way=1 -v&quot;   # reboot after
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Option B — keep SIP on (debug-only relaxed), then allowlist the binary with amfidont&lt;/strong&gt; (leaves AMFI enabled system-wide).&lt;/p&gt; 
&lt;p&gt;In Recovery:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;csrutil enable --without debug
csrutil allow-research-guests enable
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Then reboot into macOS and:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vphone-amfidont         # .build/vphone-cli.app/Contents/Resources/vphone-amfidont for local builds
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Tested Environments&lt;/h2&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Host&lt;/th&gt; 
   &lt;th&gt;iPhone&lt;/th&gt; 
   &lt;th&gt;CloudOS&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,11 27.0b2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_18.6.2_22G100&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.1-23B85&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,8 26.5.1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.0_23A341&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.1-23B85&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,8 26.5.1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.0.1_23A355&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.1-23B85&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,12 26.3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.1_23B85&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.1-23B85&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,12 26.3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.3_23D127&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.1-23B85&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,12 26.3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.3_23D127&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.3-23D128&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,12 26.3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.3.1_23D8133&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.3-23D128&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,11 26.2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.4_23E246&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,11 26.2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.5_23F77&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,11 27.0b2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.5.2_23F84&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,6 25.4.1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_26.6_23G71&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,11 27.0b2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_27.0_24A5380h&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Mac16,6 25.4.1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;17,3_27.0_24A5390f&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;26.4-23E5207q&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h2&gt;FAQ&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;&lt;code&gt;zsh: killed ./vphone-cli&lt;/code&gt;&lt;/strong&gt; — AMFI/debug restrictions aren&#39;t bypassed; see &lt;a href=&quot;https://raw.githubusercontent.com/Lakr233/vphone-cli/main/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt; (&lt;code&gt;amfi_get_out_of_my_way=1&lt;/code&gt; or &lt;code&gt;amfidont&lt;/code&gt;).&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Virtualization is not available on this hardware&lt;/code&gt;&lt;/strong&gt; — your Mac is itself a VM; PV=3 guest boot can&#39;t nest. Use a non-nested macOS 15+ host.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Stuck on &quot;Press home to continue&quot;&lt;/strong&gt; — connect via VNC and right-click (two-finger click) to simulate the home button.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;System apps won&#39;t install&lt;/strong&gt; — during iOS setup, don&#39;t pick Japan or the EU as your region (extra regulatory checks the VM can&#39;t satisfy); pick e.g. United States.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;App crashes on launch with &lt;code&gt;EXC_GUARD&lt;/code&gt; / &lt;code&gt;GUARD_TYPE_MACH_PORT&lt;/code&gt;&lt;/strong&gt; — re-patch with &lt;code&gt;vphone-cli fw patch &amp;lt;name&amp;gt; --variant &amp;lt;v&amp;gt; --force-exc-guard&lt;/code&gt;, then re-restore/install (&lt;a href=&quot;https://github.com/Lakr233/vphone-cli/issues/291&quot;&gt;#291&lt;/a&gt;). Always on for iOS 18 bases.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Install a &lt;code&gt;.ipa&lt;/code&gt;/&lt;code&gt;.tipa&lt;/code&gt;&lt;/strong&gt; — use the running VM&#39;s Install menu (drag-drop or file picker).&lt;/p&gt; 
&lt;h2&gt;Automation&lt;/h2&gt; 
&lt;p&gt;&lt;code&gt;vphone-cli&lt;/code&gt; exposes a host control socket (&lt;code&gt;&amp;lt;bundle&amp;gt;/vphone.sock&lt;/code&gt;) for programmatic control — screenshots, touch, swipes, hardware keys, clipboard — each action returning an inline screenshot for AI-driven E2E testing. See &lt;a href=&quot;https://github.com/pluginslab/vphone-mcp&quot;&gt;vphone-mcp&lt;/a&gt; for an MCP server wrapping it.&lt;/p&gt; 
&lt;h2&gt;Acknowledgements&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/wh1te4ever/super-tart-vphone-writeup&quot;&gt;wh1te4ever/super-tart-vphone-writeup&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/62305bb64cb24fac2188ae0ebb53466afee34167bc2184ce6014817509540e1a/Lakr233/vphone-cli" medium="image" />
      
    </item>
    
    <item>
      <title>utmapp/UTM</title>
      <link>https://github.com/utmapp/UTM</link>
      <description>&lt;p&gt;Virtual machines for iOS and macOS&lt;/p&gt;&lt;hr&gt;&lt;h1&gt;UTM&lt;/h1&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/utmapp/UTM/actions?query=event%3Arelease+workflow%3ABuild&quot;&gt;&lt;img src=&quot;https://github.com/utmapp/UTM/workflows/Build/badge.svg?branch=main&amp;amp;event=push&quot; alt=&quot;Build&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;It is possible to invent a single machine which can be used to compute any computable sequence.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;-- &lt;cite&gt;Alan Turing, 1936&lt;/cite&gt;&lt;/p&gt; 
&lt;p&gt;UTM is a full featured system emulator and virtual machine host for iOS and macOS. It is based off of QEMU. In short, it allows you to run Windows, Linux, and more on your Mac, iPhone, and iPad. More information at &lt;a href=&quot;https://getutm.app/&quot;&gt;https://getutm.app/&lt;/a&gt; and &lt;a href=&quot;https://mac.getutm.app/&quot;&gt;https://mac.getutm.app/&lt;/a&gt;&lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img width=&quot;450px&quot; alt=&quot;UTM running on an iPhone&quot; src=&quot;https://raw.githubusercontent.com/utmapp/UTM/main/screen.png&quot; /&gt; &lt;br /&gt; &lt;img width=&quot;450px&quot; alt=&quot;UTM running on a MacBook&quot; src=&quot;https://raw.githubusercontent.com/utmapp/UTM/main/screenmac.png&quot; /&gt; &lt;/p&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Full system emulation (MMU, devices, etc) using QEMU&lt;/li&gt; 
 &lt;li&gt;30+ processors supported including x86_64, ARM64, and RISC-V&lt;/li&gt; 
 &lt;li&gt;VGA graphics mode using SPICE and QXL&lt;/li&gt; 
 &lt;li&gt;Text terminal mode&lt;/li&gt; 
 &lt;li&gt;USB devices&lt;/li&gt; 
 &lt;li&gt;JIT based acceleration using QEMU TCG&lt;/li&gt; 
 &lt;li&gt;Frontend designed from scratch for macOS 11 and iOS 11+ using the latest and greatest APIs&lt;/li&gt; 
 &lt;li&gt;Create, manage, run VMs directly from your device&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Additional macOS Features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Hardware accelerated virtualization using Hypervisor.framework and QEMU&lt;/li&gt; 
 &lt;li&gt;Boot macOS guests with Virtualization.framework on macOS 12+&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;UTM SE&lt;/h2&gt; 
&lt;p&gt;UTM/QEMU requires dynamic code generation (JIT) for maximum performance. JIT on iOS devices require either a jailbroken device, or one of the various workarounds found for specific versions of iOS (see &quot;Install&quot; for more details).&lt;/p&gt; 
&lt;p&gt;UTM SE (&quot;slow edition&quot;) uses a &lt;a href=&quot;https://github.com/ktemkin/qemu/raw/with_tcti/tcg/aarch64-tcti/README.md&quot;&gt;threaded interpreter&lt;/a&gt; which performs better than a traditional interpreter but still slower than JIT. This technique is similar to what &lt;a href=&quot;https://github.com/ish-app/ish&quot;&gt;iSH&lt;/a&gt; does for dynamic execution. As a result, UTM SE does not require jailbreaking or any JIT workarounds and can be sideloaded as a regular app.&lt;/p&gt; 
&lt;p&gt;To optimize for size and build times, only the following architectures are included in UTM SE: ARM, PPC, RISC-V, and x86 (all with both 32-bit and 64-bit variants).&lt;/p&gt; 
&lt;h2&gt;Install&lt;/h2&gt; 
&lt;p&gt;UTM (SE) for iOS: &lt;a href=&quot;https://getutm.app/install/&quot;&gt;https://getutm.app/install/&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;UTM is also available for macOS: &lt;a href=&quot;https://mac.getutm.app/&quot;&gt;https://mac.getutm.app/&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Development&lt;/h2&gt; 
&lt;h3&gt;&lt;a href=&quot;https://raw.githubusercontent.com/utmapp/UTM/main/Documentation/MacDevelopment.md&quot;&gt;macOS Development&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;&lt;a href=&quot;https://raw.githubusercontent.com/utmapp/UTM/main/Documentation/iOSDevelopment.md&quot;&gt;iOS Development&lt;/a&gt;&lt;/h3&gt; 
&lt;h2&gt;Related&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/ish-app/ish&quot;&gt;iSH&lt;/a&gt;: emulates a usermode Linux terminal interface for running x86 Linux applications on iOS&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/holzschu/a-shell&quot;&gt;a-shell&lt;/a&gt;: packages common Unix commands and utilities built natively for iOS and accessible through a terminal interface&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;UTM is distributed under the permissive Apache 2.0 license. However, it uses several (L)GPL components. Most are dynamically linked but the gstreamer plugins are statically linked and parts of the code are taken from qemu. Please be aware of this if you intend on redistributing this application.&lt;/p&gt; 
&lt;p&gt;Some icons made by &lt;a href=&quot;https://www.freepik.com&quot;&gt;Freepik&lt;/a&gt; from &lt;a href=&quot;https://www.flaticon.com/&quot;&gt;www.flaticon.com&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Additionally, UTM frontend depends on the following MIT/BSD License components:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/hackiftekhar/IQKeyboardManager&quot;&gt;IQKeyboardManager&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/migueldeicaza/SwiftTerm&quot;&gt;SwiftTerm&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/weichsel/ZIPFoundation&quot;&gt;ZIP Foundation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/futuretap/InAppSettingsKit&quot;&gt;InAppSettingsKit&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Continuous integration hosting is provided by &lt;a href=&quot;https://www.macstadium.com/opensource&quot;&gt;MacStadium&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://www.macstadium.com&quot;&gt;&lt;img src=&quot;https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png&quot; alt=&quot;MacStadium logo&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/90f13108532c118562379b317bf09febe03e9741d3ca7b2d065d6a6093a8497c/utmapp/UTM" medium="image" />
      
    </item>
    
    <item>
      <title>BarutSRB/OmniWM</title>
      <link>https://github.com/BarutSRB/OmniWM</link>
      <description>&lt;p&gt;MacOS Niri and Hyprland inspired tiling window manager that&#39;s developer signed and notorized (safe for managed enterprise environments). Aiming for parity and extra innovation.&lt;/p&gt;&lt;hr&gt;&lt;h2&gt;Demo Video&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://youtu.be/WcHjGkuD2Fc&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/WcHjGkuD2Fc/maxresdefault.jpg&quot; alt=&quot;Watch the demo&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;!-- contributors:start --&gt; 
&lt;h2&gt;Contributors&lt;/h2&gt; 
&lt;p align=&quot;center&quot;&gt; Thank you to everyone who contributed to OmniWM. Your ideas and code made a real difference. &lt;/p&gt; 
&lt;hr /&gt; 
&lt;h3&gt;🏢 By Employer&lt;/h3&gt; 
&lt;table align=&quot;center&quot;&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/bitkey-oss&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/143800766?v=4&quot; width=&quot;72&quot; alt=&quot;Bitkey&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/bitkey-oss&quot;&gt;&lt;strong&gt;Bitkey&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/siketyan&quot; title=&quot;Naoki Ikeguchi&quot;&gt; &lt;img src=&quot;https://github.com/siketyan.png?size=96&quot; width=&quot;72&quot; alt=&quot;Naoki Ikeguchi&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/siketyan&quot;&gt;&lt;strong&gt;Naoki Ikeguchi&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@siketyan&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/epam&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/1589802?v=4&quot; width=&quot;72&quot; alt=&quot;EPAM Systems&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/epam&quot;&gt;&lt;strong&gt;EPAM&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Guria&quot; title=&quot;Aleksei Gurianov&quot;&gt; &lt;img src=&quot;https://github.com/Guria.png?size=96&quot; width=&quot;72&quot; alt=&quot;Aleksei Gurianov&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Guria&quot;&gt;&lt;strong&gt;Aleksei Gurianov&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@Guria&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/finanzguru&quot;&gt; &lt;img src=&quot;https://github.com/finanzguru.png?size=96&quot; width=&quot;72&quot; alt=&quot;Finanzguru&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/finanzguru&quot;&gt;&lt;strong&gt;Finanzguru&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/jthomaschewski&quot; title=&quot;Janek Thomaschewski&quot;&gt; &lt;img src=&quot;https://github.com/jthomaschewski.png?size=96&quot; width=&quot;72&quot; alt=&quot;Janek Thomaschewski&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/jthomaschewski&quot;&gt;&lt;strong&gt;Janek Thomaschewski&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@jthomaschewski&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/github&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/9919?v=4&quot; width=&quot;72&quot; alt=&quot;GitHub&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/github&quot;&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/RyanHecht&quot; title=&quot;Ryan Hecht&quot;&gt; &lt;img src=&quot;https://github.com/RyanHecht.png?size=96&quot; width=&quot;72&quot; alt=&quot;Ryan Hecht&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/RyanHecht&quot;&gt;&lt;strong&gt;Ryan Hecht&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@RyanHecht&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/google&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/1342004?v=4&quot; width=&quot;72&quot; alt=&quot;Google&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/google&quot;&gt;&lt;strong&gt;Google&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/MuhammadKh&quot; title=&quot;muhammadkh&quot;&gt; &lt;img src=&quot;https://github.com/MuhammadKh.png?size=96&quot; width=&quot;72&quot; alt=&quot;muhammadkh&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/MuhammadKh&quot;&gt;&lt;strong&gt;muhammadkh&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@MuhammadKh&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://luxor.tech&quot;&gt; &lt;img src=&quot;https://github.com/LuxorLabs.png?size=96&quot; width=&quot;72&quot; alt=&quot;Luxor Labs&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://luxor.tech&quot;&gt;&lt;strong&gt;Luxor Labs&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/albertilagan&quot; title=&quot;Albert Ilagan&quot;&gt; &lt;img src=&quot;https://github.com/albertilagan.png?size=96&quot; width=&quot;72&quot; alt=&quot;Albert Ilagan&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/albertilagan&quot;&gt;&lt;strong&gt;Albert Ilagan&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@albertilagan&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://www.reactsquad.io&quot;&gt; &lt;img src=&quot;https://cdn.prod.website-files.com/657d97b1704ec3bbd13b7b7f/65ae5ba5042fdf11343fdcae_reactsquad-webclipV2.png&quot; width=&quot;72&quot; alt=&quot;ReactSquad&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://www.reactsquad.io&quot;&gt;&lt;strong&gt;ReactSquad&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/janhesters&quot; title=&quot;Jan Hesters&quot;&gt; &lt;img src=&quot;https://github.com/janhesters.png?size=96&quot; width=&quot;72&quot; alt=&quot;Jan Hesters&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/janhesters&quot;&gt;&lt;strong&gt;Jan Hesters&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@janhesters&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/spotify&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/251374?v=4&quot; width=&quot;72&quot; alt=&quot;Spotify&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/spotify&quot;&gt;&lt;strong&gt;Spotify&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Cy6erBr4in&quot; title=&quot;Alexander Dergachev&quot;&gt; &lt;img src=&quot;https://github.com/Cy6erBr4in.png?size=96&quot; width=&quot;72&quot; alt=&quot;Alexander Dergachev&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Cy6erBr4in&quot;&gt;&lt;strong&gt;Alexander Dergachev&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@Cy6erBr4in&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://www.vhf.com&quot;&gt; &lt;img src=&quot;https://www.google.com/s2/favicons?domain=www.vhf.com&amp;amp;sz=96&quot; width=&quot;72&quot; alt=&quot;vhf&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://www.vhf.com&quot;&gt;&lt;strong&gt;vhf&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/lgerlinski&quot; title=&quot;Lukas Gerlinski&quot;&gt; &lt;img src=&quot;https://github.com/lgerlinski.png?size=96&quot; width=&quot;72&quot; alt=&quot;Lukas Gerlinski&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/lgerlinski&quot;&gt;&lt;strong&gt;Lukas Gerlinski&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@lgerlinski&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://github.com/viber&quot;&gt; &lt;img src=&quot;https://avatars.githubusercontent.com/u/966410?v=4&quot; width=&quot;72&quot; alt=&quot;Viber&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/viber&quot;&gt;&lt;strong&gt;Viber&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/YuriNachos&quot; title=&quot;Yuri Chukhlib&quot;&gt; &lt;img src=&quot;https://github.com/YuriNachos.png?size=96&quot; width=&quot;72&quot; alt=&quot;Yuri Chukhlib&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/YuriNachos&quot;&gt;&lt;strong&gt;Yuri Chukhlib&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@YuriNachos&lt;/sub&gt; &lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;h3&gt;🎓 By Education&lt;/h3&gt; 
&lt;table align=&quot;center&quot;&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://www.au.edu/&quot;&gt; &lt;img src=&quot;https://www.google.com/s2/favicons?domain=www.au.edu&amp;amp;sz=96&quot; width=&quot;72&quot; alt=&quot;Assumption University of Thailand&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://www.au.edu/&quot;&gt;&lt;strong&gt;Assumption University of Thailand&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/t1dotdev&quot; title=&quot;Panuphong Burakitphachai&quot;&gt; &lt;img src=&quot;https://github.com/t1dotdev.png?size=96&quot; width=&quot;72&quot; alt=&quot;Panuphong Burakitphachai&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/t1dotdev&quot;&gt;&lt;strong&gt;Panuphong Burakitphachai&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@t1dotdev&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://lnu.se/en/&quot;&gt; &lt;img src=&quot;https://www.google.com/s2/favicons?domain=lnu.se&amp;amp;sz=96&quot; width=&quot;72&quot; alt=&quot;Linnaeus University&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://lnu.se/en/&quot;&gt;&lt;strong&gt;Linnaeus University&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/balazshevesi&quot; title=&quot;Balazs Hevesi&quot;&gt; &lt;img src=&quot;https://github.com/balazshevesi.png?size=96&quot; width=&quot;72&quot; alt=&quot;Balazs Hevesi&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/balazshevesi&quot;&gt;&lt;strong&gt;Balazs Hevesi&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@balazshevesi&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://www.ntu.edu.sg/&quot;&gt; &lt;img src=&quot;https://www.google.com/s2/favicons?domain=www.ntu.edu.sg&amp;amp;sz=96&quot; width=&quot;72&quot; alt=&quot;NTU Singapore&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://www.ntu.edu.sg/&quot;&gt;&lt;strong&gt;NTU Singapore&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/holmns&quot; title=&quot;Nawat Suangburanakul&quot;&gt; &lt;img src=&quot;https://github.com/holmns.png?size=96&quot; width=&quot;72&quot; alt=&quot;Nawat Suangburanakul&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/holmns&quot;&gt;&lt;strong&gt;Nawat Suangburanakul&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@holmns&lt;/sub&gt; &lt;/td&gt; 
   &lt;td align=&quot;center&quot; valign=&quot;top&quot;&gt; &lt;a href=&quot;https://www.sustech.edu.cn/en/&quot;&gt; &lt;img src=&quot;https://www.google.com/s2/favicons?domain=www.sustech.edu.cn&amp;amp;sz=96&quot; width=&quot;72&quot; alt=&quot;SUSTech&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://www.sustech.edu.cn/en/&quot;&gt;&lt;strong&gt;SUSTech&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;━━━━━━━━&lt;/sub&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Yang-Yiming&quot; title=&quot;Yang-Yiming&quot;&gt; &lt;img src=&quot;https://github.com/Yang-Yiming.png?size=96&quot; width=&quot;72&quot; alt=&quot;Yang-Yiming&quot; /&gt; &lt;/a&gt; &lt;br /&gt; &lt;a href=&quot;https://github.com/Yang-Yiming&quot;&gt;&lt;strong&gt;Yang-Yiming&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt; &lt;sub&gt;@Yang-Yiming&lt;/sub&gt; &lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;h3&gt;✨ All Contributors&lt;/h3&gt; 
&lt;table align=&quot;center&quot;&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td nowrap&gt; &lt;a href=&quot;https://github.com/adelin-b&quot; title=&quot;Adelin Berard&quot;&gt; &lt;img src=&quot;https://github.com/adelin-b.png?size=96&quot; width=&quot;72&quot; alt=&quot;Adelin Berard&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/albertilagan&quot; title=&quot;Albert Ilagan&quot;&gt; &lt;img src=&quot;https://github.com/albertilagan.png?size=96&quot; width=&quot;72&quot; alt=&quot;Albert Ilagan&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/Guria&quot; title=&quot;Aleksei Gurianov&quot;&gt; &lt;img src=&quot;https://github.com/Guria.png?size=96&quot; width=&quot;72&quot; alt=&quot;Aleksei Gurianov&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/Cy6erBr4in&quot; title=&quot;Alexander Dergachev&quot;&gt; &lt;img src=&quot;https://github.com/Cy6erBr4in.png?size=96&quot; width=&quot;72&quot; alt=&quot;Alexander Dergachev&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/gloomy-breaker&quot; title=&quot;Ayaan Sandhu&quot;&gt; &lt;img src=&quot;https://github.com/gloomy-breaker.png?size=96&quot; width=&quot;72&quot; alt=&quot;Ayaan Sandhu&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/balazshevesi&quot; title=&quot;Balazs Hevesi&quot;&gt; &lt;img src=&quot;https://github.com/balazshevesi.png?size=96&quot; width=&quot;72&quot; alt=&quot;Balazs Hevesi&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/chen259456754&quot; title=&quot;chen259456754&quot;&gt; &lt;img src=&quot;https://github.com/chen259456754.png?size=96&quot; width=&quot;72&quot; alt=&quot;chen259456754&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/nekonora&quot; title=&quot;Filippo Zaffoni&quot;&gt; &lt;img src=&quot;https://github.com/nekonora.png?size=96&quot; width=&quot;72&quot; alt=&quot;Filippo Zaffoni&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/henry-p&quot; title=&quot;Henry Perschk&quot;&gt; &lt;img src=&quot;https://github.com/henry-p.png?size=96&quot; width=&quot;72&quot; alt=&quot;Henry Perschk&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/janhesters&quot; title=&quot;Jan Hesters&quot;&gt; &lt;img src=&quot;https://github.com/janhesters.png?size=96&quot; width=&quot;72&quot; alt=&quot;Jan Hesters&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/jthomaschewski&quot; title=&quot;Janek Thomaschewski&quot;&gt; &lt;img src=&quot;https://github.com/jthomaschewski.png?size=96&quot; width=&quot;72&quot; alt=&quot;Janek Thomaschewski&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/jcardama&quot; title=&quot;Jose Cardama&quot;&gt; &lt;img src=&quot;https://github.com/jcardama.png?size=96&quot; width=&quot;72&quot; alt=&quot;Jose Cardama&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/lgerlinski&quot; title=&quot;Lukas Gerlinski&quot;&gt; &lt;img src=&quot;https://github.com/lgerlinski.png?size=96&quot; width=&quot;72&quot; alt=&quot;Lukas Gerlinski&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/zucram&quot; title=&quot;Marcus Harlid Davin&quot;&gt; &lt;img src=&quot;https://github.com/zucram.png?size=96&quot; width=&quot;72&quot; alt=&quot;Marcus Harlid Davin&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/mkdir700&quot; title=&quot;mkdir700&quot;&gt; &lt;img src=&quot;https://github.com/mkdir700.png?size=96&quot; width=&quot;72&quot; alt=&quot;mkdir700&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/zwo-bot&quot; title=&quot;mm&quot;&gt; &lt;img src=&quot;https://github.com/zwo-bot.png?size=96&quot; width=&quot;72&quot; alt=&quot;mm&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/MuhammadKh&quot; title=&quot;muhammadkh&quot;&gt; &lt;img src=&quot;https://github.com/MuhammadKh.png?size=96&quot; width=&quot;72&quot; alt=&quot;muhammadkh&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/siketyan&quot; title=&quot;Naoki Ikeguchi&quot;&gt; &lt;img src=&quot;https://github.com/siketyan.png?size=96&quot; width=&quot;72&quot; alt=&quot;Naoki Ikeguchi&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/holmns&quot; title=&quot;Nawat Suangburanakul&quot;&gt; &lt;img src=&quot;https://github.com/holmns.png?size=96&quot; width=&quot;72&quot; alt=&quot;Nawat Suangburanakul&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/t1dotdev&quot; title=&quot;Panuphong Burakitphachai&quot;&gt; &lt;img src=&quot;https://github.com/t1dotdev.png?size=96&quot; width=&quot;72&quot; alt=&quot;Panuphong Burakitphachai&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/georgebastille&quot; title=&quot;Rich Hanes&quot;&gt; &lt;img src=&quot;https://github.com/georgebastille.png?size=96&quot; width=&quot;72&quot; alt=&quot;Rich Hanes&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/1Pio&quot; title=&quot;rPio&quot;&gt; &lt;img src=&quot;https://github.com/1Pio.png?size=96&quot; width=&quot;72&quot; alt=&quot;rPio&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/RyanHecht&quot; title=&quot;Ryan Hecht&quot;&gt; &lt;img src=&quot;https://github.com/RyanHecht.png?size=96&quot; width=&quot;72&quot; alt=&quot;Ryan Hecht&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/chenhaozhenss&quot; title=&quot;Williamufo&quot;&gt; &lt;img src=&quot;https://github.com/chenhaozhenss.png?size=96&quot; width=&quot;72&quot; alt=&quot;Williamufo&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/Yang-Yiming&quot; title=&quot;Yang-Yiming&quot;&gt; &lt;img src=&quot;https://github.com/Yang-Yiming.png?size=96&quot; width=&quot;72&quot; alt=&quot;Yang-Yiming&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/YuriNachos&quot; title=&quot;Yuri Chukhlib&quot;&gt; &lt;img src=&quot;https://github.com/YuriNachos.png?size=96&quot; width=&quot;72&quot; alt=&quot;Yuri Chukhlib&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;https://github.com/zicochaos&quot; title=&quot;Zicochaos&quot;&gt; &lt;img src=&quot;https://github.com/zicochaos.png?size=96&quot; width=&quot;72&quot; alt=&quot;Zicochaos&quot; /&gt; &lt;/a&gt; &lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;!-- contributors:end --&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://img.shields.io/badge/macOS-26.0%2B-green?logo=apple&amp;amp;logoColor=white&quot; alt=&quot;macOS&quot; /&gt; &lt;img src=&quot;https://img.shields.io/badge/Apple%20Silicon-supported-green?logo=apple&amp;amp;logoColor=white&quot; alt=&quot;Apple Silicon&quot; /&gt; &lt;img src=&quot;https://custom-icon-badges.demolab.com/badge/OpenAI-Assisted-green?logo=openai&amp;amp;logoColor=white&quot; alt=&quot;OpenAI Assisted&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://trendshift.io/repositories/16758&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://trendshift.io/api/badge/repositories/16758&quot; alt=&quot;BarutSRB%2FOmniWM | Trendshift&quot; style=&quot;width: 250px; height: 55px;&quot; width=&quot;250&quot; height=&quot;55&quot; /&gt;&lt;/a&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://trendshift.io/repositories/16758?utm_source=trendshift-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-trendshift-16758&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://trendshift.io/api/badge/trendshift/repositories/16758/weekly?language=Swift&quot; alt=&quot;BarutSRB%2FOmniWM | Trendshift&quot; width=&quot;250&quot; height=&quot;55&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://trendshift.io/repositories/16758?utm_source=trendshift-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-trendshift-16758&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://trendshift.io/api/badge/trendshift/repositories/16758/monthly?language=Swift&quot; alt=&quot;BarutSRB%2FOmniWM | Trendshift&quot; width=&quot;250&quot; height=&quot;55&quot; /&gt;&lt;/a&gt; &lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Real quake/sticky terminal using ghostty&#39;s libghostty&lt;/li&gt; 
 &lt;li&gt;macOS native tab support&lt;/li&gt; 
 &lt;li&gt;IPC/CLI&lt;/li&gt; 
 &lt;li&gt;Scrathpad/Sticky windows for any app&lt;/li&gt; 
 &lt;li&gt;Niri Overview&lt;/li&gt; 
 &lt;li&gt;Unified command palette for windows and app menus&lt;/li&gt; 
 &lt;li&gt;App menu anywhere&lt;/li&gt; 
 &lt;li&gt;Niri tabbed columns and Dwindle tile groups&lt;/li&gt; 
 &lt;li&gt;Niri and Dwindle layout&lt;/li&gt; 
 &lt;li&gt;Hide/unhide status bar icons (Similar to Ice Bar)&lt;/li&gt; 
 &lt;li&gt;Keep awake (Similar to Caffeine)&lt;/li&gt; 
 &lt;li&gt;Interactive workspace/app icon bar&lt;/li&gt; 
 &lt;li&gt;A lot more features not show in the video.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Known Limitations&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Dwindle group restore&lt;/strong&gt; - Group membership and tab order are runtime layout state and are not restored after OmniWM restarts.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Performance &amp;amp; Trust&lt;/h2&gt; 
&lt;p&gt;OmniWM is built for high responsiveness and smooth, crisp animations.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Private APIs&lt;/strong&gt; - OmniWM leverages Apple&#39;s private APIs where ever technically possible in order to reduce latency and improve window management responsiveness.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Refresh rate aware animations&lt;/strong&gt; - OmniWM targets true display refresh pacing (for example 60/120/144Hz) for animations.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;No SIP disable required&lt;/strong&gt; - OmniWM does not require System Integrity Protection (SIP) to be disabled and never will.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Always notarized official releases&lt;/strong&gt; - Official OmniWM release builds are developer signed and notarized by Apple and will stay that way.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Forever free, no limitations&lt;/strong&gt; - OmniWM is and will remain free to use forever, with no subscriptions, feature paywalls, trial limits, or usage caps.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Requirements&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;macOS 26+ (Tahoe) on Apple Silicon&lt;/li&gt; 
 &lt;li&gt;Accessibility permissions (prompted on launch)&lt;/li&gt; 
 &lt;li&gt;Input Monitoring permission when using a System Hyper Trigger&lt;/li&gt; 
 &lt;li&gt;Displays have separate spaces &lt;strong&gt;ON&lt;/strong&gt; (the macOS default; OmniWM pauses window management until it is enabled)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;h3&gt;Homebrew&lt;/h3&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew tap BarutSRB/tap
brew install omniwm
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Nix&lt;/h3&gt; 
&lt;p&gt;OmniWM supports both community-maintained Nix packages below. They install official OmniWM release artifacts, while their Nix expressions are maintained by DoomHammer and DavSanchez respectively.&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Package&lt;/th&gt; 
   &lt;th&gt;Best for&lt;/th&gt; 
   &lt;th&gt;Packaging difference&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;a href=&quot;https://nur.nix-community.org/repos/doomhammer/&quot;&gt;DoomHammer NUR package&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Fast release tracking&lt;/td&gt; 
   &lt;td&gt;Its current &lt;code&gt;unzip&lt;/code&gt; extraction does not preserve the release&#39;s valid Developer ID signature, and it installs the app bundle without exposing &lt;code&gt;omniwmctl&lt;/code&gt; on &lt;code&gt;PATH&lt;/code&gt;.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;a href=&quot;https://github.com/DavSanchez/nix-dotfiles/raw/master/pkgs/omniwm.nix&quot;&gt;DavSanchez package&lt;/a&gt; and &lt;a href=&quot;https://github.com/DavSanchez/nix-dotfiles/raw/master/modules/home/omniwm.nix&quot;&gt;Home Manager module&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Signature-preserving, declarative integration&lt;/td&gt; 
   &lt;td&gt;It may trail the latest release, but its &lt;code&gt;bsdtar&lt;/code&gt; extraction preserves code signing and it provides &lt;code&gt;omniwmctl&lt;/code&gt;, Home Manager settings, and launchd integration.&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;Install the fast-tracking DoomHammer package directly:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nix profile install github:DoomHammer/nur-packages#omniwm
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Existing NUR configurations can use &lt;code&gt;nur.repos.doomhammer.omniwm&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;Install the signature-preserving DavSanchez package directly:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nix profile install github:DavSanchez/nix-dotfiles#omniwm
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For a declarative setup, use DavSanchez&#39;s exported &lt;a href=&quot;https://github.com/DavSanchez/nix-dotfiles/raw/master/modules/home/omniwm.nix&quot;&gt;&lt;code&gt;homeModules.omniwm&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;overlays.additions&lt;/code&gt;. After either installation, complete the macOS setup in steps 3-6 below.&lt;/p&gt; 
&lt;h3&gt;GitHub Releases&lt;/h3&gt; 
&lt;ol&gt; 
 &lt;li&gt;Download the latest &lt;code&gt;OmniWM.zip&lt;/code&gt; from &lt;a href=&quot;https://github.com/BarutSRB/OmniWM/releases&quot;&gt;Releases&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Extract and move &lt;code&gt;OmniWM.app&lt;/code&gt; to &lt;code&gt;/Applications&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;In System Settings &amp;gt; Desktop &amp;amp; Dock &amp;gt; Mission Control, turn &lt;strong&gt;ON&lt;/strong&gt; &lt;code&gt;Displays have separate Spaces&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Log out of macOS and log back in for that change to take effect unless you had it on already&lt;/li&gt; 
 &lt;li&gt;Launch OmniWM and grant Accessibility permissions when prompted&lt;/li&gt; 
 &lt;li&gt;To use a System Hyper Trigger, grant Input Monitoring from Settings &amp;gt; Hotkeys&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2&gt;Updates&lt;/h2&gt; 
&lt;p&gt;OmniWM checks for updates by default.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;On launch, OmniWM polls the latest GitHub release at most once per day.&lt;/li&gt; 
 &lt;li&gt;Updates stay manual. OmniWM does not auto-download or auto-install a new release.&lt;/li&gt; 
 &lt;li&gt;When a newer release is available, OmniWM shows a centered popup with release notes and actions for &lt;code&gt;Open Release Page&lt;/code&gt;, &lt;code&gt;Copy brew upgrade omniwm&lt;/code&gt;, &lt;code&gt;Skip This Version&lt;/code&gt;, and &lt;code&gt;Not Now&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;You can control this from &lt;code&gt;Settings &amp;gt; General &amp;gt; Updates&lt;/code&gt; or trigger a manual check from the status bar menu with &lt;code&gt;Check for Updates...&lt;/code&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Documentation&lt;/h2&gt; 
&lt;p&gt;The documentation hub lives in &lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/index.md&quot;&gt;&lt;code&gt;docs/index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/index.md&quot;&gt;Documentation Home&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/ARCHITECTURE.md&quot;&gt;Architecture Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/IPC-CLI.md&quot;&gt;IPC &amp;amp; CLI Reference&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/CONTRIBUTING.md&quot;&gt;Contribution Docs&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/CONTRIBUTING.md&quot;&gt;Canonical Contributing Guide&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;IPC and CLI&lt;/h2&gt; 
&lt;p&gt;OmniWM ships with a bundled CLI, &lt;code&gt;omniwmctl&lt;/code&gt;, for automation and scripting.&lt;/p&gt; 
&lt;p&gt;IPC is disabled by default. Enable &lt;code&gt;Enable IPC&lt;/code&gt; from the menu bar before using the CLI or any automation.&lt;/p&gt; 
&lt;p&gt;For setup, installation options, commands, queries, rules, subscriptions, and security details, see &lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/IPC-CLI.md&quot;&gt;docs/IPC-CLI.md&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Quick Start&lt;/h2&gt; 
&lt;ol&gt; 
 &lt;li&gt;Launch OmniWM from your Applications folder&lt;/li&gt; 
 &lt;li&gt;In System Settings &amp;gt; Desktop &amp;amp; Dock &amp;gt; Mission Control, turn &lt;strong&gt;ON&lt;/strong&gt; &lt;code&gt;Displays have separate Spaces&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Log out of macOS and log back in for that change to take effect unless you had it on already&lt;/li&gt; 
 &lt;li&gt;Grant Accessibility permissions in System Settings &amp;gt; Privacy &amp;amp; Security &amp;gt; Accessibility&lt;/li&gt; 
 &lt;li&gt;Windows will automatically tile in columns&lt;/li&gt; 
 &lt;li&gt;Keep one macOS Space per display and navigate with OmniWM workspaces; extra native Spaces are tolerated (their windows are left to macOS, not tiled)&lt;/li&gt; 
 &lt;li&gt;Use the default shortcuts in &lt;code&gt;Keyboard Shortcuts&lt;/code&gt; to navigate between windows&lt;/li&gt; 
 &lt;li&gt;Click the menu bar icon to access Settings, including &lt;code&gt;Settings &amp;gt; General &amp;gt; Updates&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Use &lt;code&gt;Check for Updates...&lt;/code&gt; from the status bar menu whenever you want to run a manual update check&lt;/li&gt; 
 &lt;li&gt;In case you freak out and don&#39;t see all your status bar icons, relax, OmniWM hides the menu-bar icons you selected in &lt;code&gt;Settings &amp;gt; Hidden Bar&lt;/code&gt;. Right-click OmniWM&#39;s status bar icon to open the Hidden Icons Bar and click any icon to use it.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2&gt;User Guide&lt;/h2&gt; 
&lt;h3&gt;Multi-Monitor Setup&lt;/h3&gt; 
&lt;p&gt;OmniWM uses two display maps for different jobs:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;Open &lt;strong&gt;System Settings &amp;gt; Displays &amp;gt; Arrange&lt;/strong&gt;. Put the physically largest or widest display at the bottom. Place the next smaller display above and to its right so its bottom-left corner touches the lower display&#39;s top-right corner. Continue the same staircase for every additional display. This macOS map is a technical arrangement used for actual window placement; it does not need to look like your desk.&lt;/li&gt; 
 &lt;li&gt;Open &lt;strong&gt;OmniWM Settings &amp;gt; Monitors&lt;/strong&gt; and arrange the OmniWM routing map to match where the displays really sit on your desk. Keep every display connected by a left, right, up, or down edge; diagonal-only displays cannot exchange directional focus, window moves, or mouse warp.&lt;/li&gt; 
 &lt;li&gt;Leave &lt;strong&gt;Mouse Warp&lt;/strong&gt; turned on for the recommended experience. It lets the pointer cross between displays according to the real-desk OmniWM map even though macOS uses the staircase.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The setup assistant opens automatically when OmniWM first sees multiple displays. To review or redo it later, choose &lt;strong&gt;Run Monitor Setup…&lt;/strong&gt; in &lt;strong&gt;Settings &amp;gt; Monitors&lt;/strong&gt;. The assistant&#39;s &lt;strong&gt;Show Numbers on Screens&lt;/strong&gt; action helps match each physical display to its tile.&lt;/p&gt; 
&lt;h3&gt;Layout Modes&lt;/h3&gt; 
&lt;p&gt;OmniWM offers two layout engines that you can switch between per workspace:&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Niri (Scrolling Columns)&lt;/strong&gt; - Windows arranged in vertical columns that scroll horizontally. Each column can have multiple stacked windows or be &quot;tabbed&quot; (multiple windows, one visible at a time). Best for wide monitors with many windows.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Hyprland Dwindle (BSP)&lt;/strong&gt; - Binary space partition layout that recursively divides screen space. Each new window splits the space in half, and a tile can group multiple windows as tabs. Best for traditional tiling with predictable layouts.&lt;/p&gt; 
&lt;p&gt;Use the &lt;code&gt;Toggle Workspace Layout&lt;/code&gt; shortcut below to switch layouts per workspace or configure them in GUI settings.&lt;/p&gt; 
&lt;h3&gt;Keyboard Shortcuts&lt;/h3&gt; 
&lt;p&gt;All shortcuts are customizable in Settings &amp;gt; Hotkeys. &lt;code&gt;Hyper&lt;/code&gt; is the literal &lt;code&gt;Control + Option + Shift + Command&lt;/code&gt; chord by default; which modifiers make up &lt;code&gt;Hyper&lt;/code&gt; is configurable in Settings &amp;gt; Hotkeys (for example, exclude &lt;code&gt;Shift&lt;/code&gt; to keep &lt;code&gt;Hyper + Shift + …&lt;/code&gt; free for extra bindings). Changing the combination retargets every shortcut that currently resolves to &lt;code&gt;Hyper&lt;/code&gt; onto the new one, so the shortcut list updates in place as you toggle the modifiers. Optionally pick a &lt;strong&gt;System Hyper Trigger&lt;/strong&gt; — a single key (Caps Lock, F13–F20, or a left- or right-side modifier) or an extra mouse button that acts as &lt;code&gt;Hyper&lt;/code&gt; while held (this needs Input Monitoring permission). Leave the trigger as &lt;code&gt;None&lt;/code&gt; if you already produce &lt;code&gt;Hyper&lt;/code&gt; another way, such as a Karabiner Elements remap. The tables below list all the default hotkeys:&lt;/p&gt; 
&lt;p&gt;Layout legend:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;Shared&lt;/code&gt; works in any active layout.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Niri&lt;/code&gt; works only when the active workspace uses the Niri layout.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Dwindle&lt;/code&gt; works only when the active workspace uses the Dwindle layout.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Workspace&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Switch to Workspace 1-9&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + 1-9&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Window to Workspace 1-9&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + 1-9&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Switch to Previous Workspace (Back and Forth)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Tab&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Switch to Next Workspace&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Switch to Previous Workspace (Sequential)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Window to Workspace Up&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Up Arrow&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Window to Workspace Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Down Arrow&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Column to Workspace 1-9&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Column to Workspace Up&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Page Up&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Column to Workspace Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Page Down&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h4&gt;Focus&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Left / Right / Up / Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Down or Top / Up or Bottom&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Previous Window&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Tab&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Traverse Backward&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Traverse Forward&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus First Column&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Home&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Last Column&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + End&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Column 1-9&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + 1-9&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Command Palette&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Space&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Open Menu Anywhere&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + M&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Workspace Bar&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Hidden Icons Bar&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Quake Terminal&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + `&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Overview&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + O&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h4&gt;Move Window&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Left / Right / Up / Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Reorder Window Up / Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h4&gt;Monitor&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Next Monitor&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Command + Tab&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Previous Monitor&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus Last Monitor&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Command + `&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Workspace to Left / Right / Up / Down Monitor&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Window to Left / Right / Up / Down Monitor&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;The workspace-to-monitor actions target the active workspace and intentionally use the same temporary runtime override as &lt;code&gt;omniwmctl workspace move-to-monitor --force&lt;/code&gt;. They do not rewrite the workspace&#39;s Home Monitor or swap workspaces, and unsafe fullscreen, hidden-app, scratchpad, or focus states still block the move.&lt;/p&gt; 
&lt;p&gt;The window-to-monitor actions send the focused window directly to the current workspace on the adjacent routed display, independently of &lt;strong&gt;Move Window Across Monitor at Edge&lt;/strong&gt;. They do not wrap when no monitor exists in that direction. &lt;strong&gt;Follow Window to Monitor&lt;/strong&gt; controls whether focus follows the window; when it is off, you remain in the source workspace.&lt;/p&gt; 
&lt;h4&gt;Layout&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Fullscreen&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Return&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Native Fullscreen&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Balance Sizes&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + B&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Cycle Size Forward&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + .&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Cycle Size Backward&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + ,&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move to Root&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Split&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Swap Split&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Grow Horizontally / Vertically&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Shrink Horizontally / Vertically&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Grow / Shrink Focused Window&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Preselect Left / Right / Up / Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Clear Preselection&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Raise All Floating Windows&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + R&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Focused Window Floating&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Assign Focused Window to Scratchpad&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Scratchpad Window&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Workspace Layout&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + L&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h4&gt;Container and Column&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Layout&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Container Left / Right&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Left / Right Arrow&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Shared&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move Container Up / Down&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Unassigned&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Dwindle&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Column Tabbed&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + T&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Toggle Container Full Primary Span&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + F&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Niri&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;The daily &lt;code&gt;Focus&lt;/code&gt; and &lt;code&gt;Move&lt;/code&gt; shortcuts adapt to the active layout. In Niri, &lt;code&gt;Move Left / Right&lt;/code&gt; expels the focused window from a multi-window column or consumes a single-window column into its neighbor, while &lt;code&gt;Move Up / Down&lt;/code&gt; reorders within the column.&lt;/p&gt; 
&lt;h4&gt;Dwindle Groups&lt;/h4&gt; 
&lt;p&gt;Dwindle groups use the existing Focus and Move bindings, so there are no separate group shortcuts to memorize. Only the active member occupies the tile; the other members stay hidden and the clickable tab rail shows their order.&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Goal&lt;/th&gt; 
   &lt;th&gt;Default Shortcut&lt;/th&gt; 
   &lt;th&gt;Behavior&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Focus another tile&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Left / Right are always spatial. Up / Down are spatial for a singleton tile.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Select the next / previous tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Down / Up Arrow&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Within a group, Down advances and Up goes back. At the group edge OmniWM tries a spatial tile, then the configured monitor transition, and wraps locally only when neither exit succeeds.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Join a singleton into a tile or group&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Joins the focused singleton with the touching tile in that direction.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Extract the active tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Option + Shift + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;When the focused tile is grouped, extracts only its active tab onto the requested side.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Move the complete tile or group&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Control + Option + Shift + Left / Right Arrow&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Move Container&lt;/code&gt; swaps the whole structure. Up / Down are advanced, unassigned Dwindle actions.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Select an exact tab&lt;/td&gt; 
   &lt;td&gt;Click its tab rail item&lt;/td&gt; 
   &lt;td&gt;Reveals and focuses that member without changing the group order.&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;Moving a tab directly from one existing group into another is intentionally a two-step operation: extract it first, then move the resulting singleton toward the destination group. A singleton at a genuine workspace edge can still use the normal cross-monitor Move behavior; a rejected group mutation does not fall through to tile swapping or monitor movement.&lt;/p&gt; 
&lt;p&gt;The unassigned advanced actions are available in Settings &amp;gt; Hotkeys. &lt;code&gt;Focus Down or Top / Up or Bottom&lt;/code&gt; always wraps within the active Niri column or Dwindle group. &lt;code&gt;Reorder Window Up / Down&lt;/code&gt; changes the active member&#39;s position by one without wrapping. &lt;code&gt;Move Container&lt;/code&gt; is the whole-structure escape hatch and never transfers to another monitor at a workspace edge. Dwindle join/extract and Move Container operations are intentionally unavailable while Overview is open; leave Overview before changing a Dwindle tree.&lt;/p&gt; 
&lt;h4&gt;Quake Terminal (Inside Terminal)&lt;/h4&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Action&lt;/th&gt; 
   &lt;th&gt;Shortcut&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;New Tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + T&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Close Tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + W&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Next Tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Shift + ]&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Previous Tab&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Shift + [&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Next Tab (Alt)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Ctrl + Tab&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Previous Tab (Alt)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Ctrl + Shift + Tab&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Select Tab 1-9&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + 1-9&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Split Pane (Horizontal)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + D&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Split Pane (Vertical)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Shift + D&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Close Pane&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Shift + W&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Equalize Splits&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Shift + =&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Navigate Pane&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;Cmd + Option + Arrow Keys&lt;/code&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h3&gt;Features&lt;/h3&gt; 
&lt;h4&gt;Quake Terminal&lt;/h4&gt; 
&lt;p&gt;A true quake/sticky terminal (powered by Ghostty&#39;s libghostty) that slides in from the screen edge and:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Toggle it from the global shortcut shown in &lt;code&gt;Keyboard Shortcuts&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Supports multiple tabs and splits within tabs&lt;/li&gt; 
 &lt;li&gt;Tab and pane shortcuts are listed in &lt;strong&gt;Quake Terminal (Inside Terminal)&lt;/strong&gt;&lt;/li&gt; 
 &lt;li&gt;Mouse resize by dragging edges; &lt;code&gt;Option + drag&lt;/code&gt; to move (remembers size/position per monitor)&lt;/li&gt; 
 &lt;li&gt;Configure position (top/bottom/left/right/center), size, opacity, and background effect in Settings&lt;/li&gt; 
 &lt;li&gt;Choose Standard Blur with an adjustable radius or native Regular Glass/Clear Glass; switching effects preserves the saved Standard Blur radius&lt;/li&gt; 
 &lt;li&gt;Auto-hides on focus loss (optional)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Command Palette&lt;/h4&gt; 
&lt;p&gt;Quickly search windows, app menus, or clipboard history from one shared palette:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Open it from the global shortcut shown in &lt;code&gt;Keyboard Shortcuts&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Use &lt;code&gt;Tab&lt;/code&gt; / &lt;code&gt;Shift + Tab&lt;/code&gt; to cycle forward or backward through the available modes&lt;/li&gt; 
 &lt;li&gt;Use &lt;code&gt;Cmd + 1&lt;/code&gt; for &lt;code&gt;Windows&lt;/code&gt;, &lt;code&gt;Cmd + 2&lt;/code&gt; for &lt;code&gt;Menu&lt;/code&gt;, and &lt;code&gt;Cmd + 3&lt;/code&gt; for &lt;code&gt;Clipboard&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Type to fuzzy-search by window title, app name, menu item, or clipboard content&lt;/li&gt; 
 &lt;li&gt;Menu results always show keyboard shortcuts when available&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Up&lt;/code&gt; / &lt;code&gt;Down&lt;/code&gt; move the selection&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Enter&lt;/code&gt; activates the selected result&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Shift + Enter&lt;/code&gt; summons the selected window to the right when available&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Escape&lt;/code&gt; dismisses the palette&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Menu Anywhere&lt;/h4&gt; 
&lt;p&gt;Access any application&#39;s menu from your keyboard:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Shows the native menu at the cursor from a global shortcut&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Overview Mode&lt;/h4&gt; 
&lt;p&gt;See all windows at once with thumbnails:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Open it from the global shortcut shown in &lt;code&gt;Keyboard Shortcuts&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Configure the 50–150% baseline zoom plus backdrop and window-border colors in &lt;strong&gt;Settings → Overview&lt;/strong&gt;&lt;/li&gt; 
 &lt;li&gt;Click a window to focus it&lt;/li&gt; 
 &lt;li&gt;Type to filter/search windows; &lt;code&gt;Backspace&lt;/code&gt; deletes search text&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Alt (Option) + Shift + Mouse Scroll&lt;/code&gt; temporarily zooms the current overview; the next opening starts from the configured baseline&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Arrow Keys&lt;/code&gt; navigate the selection; &lt;code&gt;Tab&lt;/code&gt; / &lt;code&gt;Shift + Tab&lt;/code&gt; move horizontally, and keyboard navigation automatically scrolls the selected thumbnail into view&lt;/li&gt; 
 &lt;li&gt;Assigned structural move, reorder, consume/expel, and workspace-transfer shortcuts operate on the selected thumbnail while Overview is open&lt;/li&gt; 
 &lt;li&gt;In Niri workspaces, reorder windows and columns, consume or expel windows, move windows into or out of columns, move windows across workspaces and monitors, and move whole columns between Niri workspaces&lt;/li&gt; 
 &lt;li&gt;Adjacent-workspace fallback actions can create the next compatible unused numeric workspace when moving past the current workspace edge&lt;/li&gt; 
 &lt;li&gt;In Dwindle workspaces, Overview supports moving windows across workspaces and closing them without adding Overview-only tree placement controls&lt;/li&gt; 
 &lt;li&gt;A successful move keeps the moved window selected and activates its destination workspace and monitor behind Overview&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Option + drag&lt;/code&gt; a thumbnail onto a workspace, an exact window position, or a Niri column gap; layouts without an exact placement equivalent fall back to moving it to the destination workspace&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Command + W&lt;/code&gt; closes the selected window once per press and keeps Overview open; selection advances only after the window has closed&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Enter&lt;/code&gt;, &lt;code&gt;Escape&lt;/code&gt;, the configured Overview shortcut, and clicking the backdrop dismiss Overview and focus the current selection; &lt;code&gt;Escape&lt;/code&gt; does not clear search first&lt;/li&gt; 
 &lt;li&gt;If another application takes focus, Overview dismisses without stealing focus back&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Workspace Bar&lt;/h4&gt; 
&lt;p&gt;A visual indicator showing your workspaces:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Displays open apps per workspace&lt;/li&gt; 
 &lt;li&gt;Click to switch workspaces or jump to that app&lt;/li&gt; 
 &lt;li&gt;If dedupe option is on click the app icon to get a popup with list of all its windows to jump to&lt;/li&gt; 
 &lt;li&gt;Configure position, height, and appearance in Settings&lt;/li&gt; 
 &lt;li&gt;Exclude individual apps or choose alternate app icons across all monitors in Settings&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Workspace-bar icon overrides can also be configured in &lt;code&gt;settings.toml&lt;/code&gt;. Quote bundle IDs so TOML treats each dotted identifier as one key:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;[workspaceBar.iconOverrides]
&quot;com.example.App&quot; = &quot;icons/custom.icns&quot;
&quot;com.cmuxterm.app&quot; = &quot;bundle-resource:AppIconDark&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;code&gt;bundle-resource:&lt;/code&gt; loads a named image packaged inside the selected app. The Settings picker discovers likely app-icon resources on demand; runtime-generated or downloaded Dock icons may not be available. Absolute paths are used as written, &lt;code&gt;~&lt;/code&gt; expands to your home directory, and relative paths are resolved from the directory containing &lt;code&gt;settings.toml&lt;/code&gt;. Overrides affect only the workspace bar. A valid override takes precedence over the app&#39;s standard icon; an unavailable or invalid image falls back to the standard icon, then the dashed placeholder when no app icon is available. OmniWM does not watch image files; use Replace to reload a file changed in place.&lt;/p&gt; 
&lt;h4&gt;Hidden Bar&lt;/h4&gt; 
&lt;p&gt;Conceal selected menu-bar icons and reach them from a panel:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Concealment requires macOS 27 or later; the rest of OmniWM continues to support macOS 26&lt;/li&gt; 
 &lt;li&gt;Pick the apps to hide in &lt;code&gt;Settings &amp;gt; Hidden Bar&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Right-click (or Option-click) the OmniWM menu bar icon to open the Hidden Icons Bar; click an icon to reveal and use it&lt;/li&gt; 
 &lt;li&gt;Revealed icons re-hide automatically after a configurable interval&lt;/li&gt; 
 &lt;li&gt;An optional global hotkey is available and starts unassigned&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Tips&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Workspaces&lt;/strong&gt; - Create named workspaces in Settings to organize by project or context (You can use emojis 🥳)&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;App Rules&lt;/strong&gt; - Exclude problematic apps from tiling or assign them to specific workspaces&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Mouse&lt;/strong&gt; - On the Niri desktop, hold the configured mouse-move modifier and drag to swap tiled windows; add &lt;code&gt;Shift&lt;/code&gt; to insert into a column. The modifier defaults to &lt;code&gt;Option&lt;/code&gt; and can be changed or disabled in &lt;strong&gt;Settings → Mouse &amp;amp; Trackpad&lt;/strong&gt;. In Overview, &lt;code&gt;Option + drag&lt;/code&gt; targets a workspace, window position, or Niri column gap&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Mouse Resize&lt;/strong&gt; - Hold &lt;code&gt;Option&lt;/code&gt; and right-drag a tiled window to resize (Niri)&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Scroll Gestures (Mouse)&lt;/strong&gt; - Hold &lt;code&gt;Option + Shift + Mouse Scroll Wheel&lt;/code&gt; (default, configurable) and scroll through columns horizontally&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Trackpad Gestures&lt;/strong&gt; - Use horizontal gestures with 2/3/4 fingers (configurable); direction can be inverted (local hardware validation is limited)&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Workspace Swipe (Trackpad)&lt;/strong&gt; - Opt-in in Settings → Mouse &amp;amp; Trackpad: swipe with a configurable finger count (2/3/4) and axis (horizontal/vertical) to switch to the next/previous workspace on the monitor under the cursor, one switch per swipe; sharing the column-scroll finger count locks the axis to vertical. For vertical swipes with three or four fingers, first turn off Mission Control in  → System Settings → Trackpad → More Gestures so macOS does not intercept the gesture.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Configuration&lt;/h2&gt; 
&lt;p&gt;Access settings by clicking OmniWM&#39;s status bar icon and selecting &lt;strong&gt;Settings&lt;/strong&gt; or &lt;strong&gt;App Rules&lt;/strong&gt;. Mouse and gesture settings live in Settings under &lt;strong&gt;Mouse &amp;amp; Trackpad&lt;/strong&gt;.&lt;/p&gt; 
&lt;p&gt;OmniWM stores its editable config at &lt;code&gt;${XDG_CONFIG_HOME:-$HOME/.config}/omniwm/settings.toml&lt;/code&gt;; that file is the canonical settings source and is live-reloaded when saved from an editor.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Reveal Settings File&lt;/strong&gt; and &lt;strong&gt;Edit Settings File&lt;/strong&gt; open the canonical TOML file and recreate it from the running settings if it was deleted.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;updateChecksEnabled&lt;/code&gt; is part of the persisted settings model, so it round-trips through &lt;code&gt;settings.toml&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;Clipboard history, last-check timestamps, skipped-release state, and the persisted window restore catalog live in &lt;code&gt;${XDG_STATE_HOME:-$HOME/.local/state}/omniwm&lt;/code&gt; and stay out of dotfile-oriented config storage.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;App Rules&lt;/h2&gt; 
&lt;p&gt;Configure per-application behavior in Settings &amp;gt; App Rules:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Always Float&lt;/strong&gt; - Force specific apps to always float (e.g., calculators, preferences windows)&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Assign to Workspace&lt;/strong&gt; - Use a valid workspace assignment as the initial default whenever the matching app currently has no tracked windows. Additional windows open on the workspace active when creation began. Automatic rule reevaluation leaves managed windows in place, while explicit rule application can move them. Readmission, structural replacements, tracked transient children, and unique persisted boot-restore matches preserve their existing placement continuity.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Initial Container Primary Span (Niri)&lt;/strong&gt; - Start matching resizable windows at 5–100% when they create or claim a new container; the container remains freely resizable afterward&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Minimum Size&lt;/strong&gt; - Prevent the layout engine from sizing windows below a threshold&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Initial container primary span is a one-time seed. It controls width in horizontal orientation and height in vertical orientation. Niri&#39;s Single Window Fit still takes visual precedence for a lone window, and physical minimum-size constraints can clamp the resolved pixel size without changing the stored initial proportion.&lt;/p&gt; 
&lt;p&gt;The equivalent TOML rule uses a proportion:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;[[appRules]]
bundleId = &quot;net.kovidgoyal.kitty&quot;
initialContainerPrimarySpan = 0.5
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Building from Source&lt;/h2&gt; 
&lt;p&gt;Requirements:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;SwiftPM with Swift 6.4+&lt;/li&gt; 
 &lt;li&gt;macOS 26.0+&lt;/li&gt; 
 &lt;li&gt;Ghostty&#39;s arm64 archive (build Ghostty and copy it to &lt;code&gt;Frameworks/GhosttyKit.xcframework/macos-arm64/libghostty-internal-fat.a&lt;/code&gt;)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Use the bundled Debug launch for day-to-day development:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;make run
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;code&gt;make run&lt;/code&gt; builds, packages, development-signs, and opens &lt;code&gt;dist/OmniWM.app&lt;/code&gt; through LaunchServices. This is the canonical development launch because it gives OmniWM its normal app identity. OmniWM uses its native status bar item while Hidden Bar concealment is inactive. While concealment is active, it uses a separate fallback icon next to the workspace bar because macOS can conceal the app-owned status item with the other restricted items. This behavior applies to both bundled and raw &lt;code&gt;swift run OmniWM&lt;/code&gt; launches and is not specific to Debug builds.&lt;/p&gt; 
&lt;h2&gt;Related Forks&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/apphane-dev/nehir&quot;&gt;Nehir&lt;/a&gt;&lt;/strong&gt; is an endorsed OmniWM fork focused on a narrower, more opinionated Niri-style scrolling-column workflow. It may be friendlier for beginners who want guided defaults and a smaller feature surface, while OmniWM remains the broader upstream project with multiple layout modes and the full feature set.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/choru-k/OmniWM&quot;&gt;choru-k/OmniWM&lt;/a&gt;&lt;/strong&gt; is an interesting personal OmniWM fork experimenting with opt-in workflow layers on top of upstream OmniWM, including zone anchors for the Niri strip, a configurable F13-F20 leader-key chord menu, tabbed-column keyboard cycling, and trackpad-friendly modifier resizing. It is best read as a power-user workflow branch rather than a replacement for the main OmniWM release.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Support&lt;/h2&gt; 
&lt;p&gt;If you find OmniWM useful, consider supporting development:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/sponsors/BarutSRB&quot;&gt;GitHub Sponsors&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://paypal.me/beacon2024&quot;&gt;PayPal&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Reporting Bugs&lt;/h2&gt; 
&lt;p&gt;The best way to report a bug is from inside OmniWM: open the status-bar menu and choose &lt;strong&gt;Report a Bug…&lt;/strong&gt;. It records an optional diagnostics trace, creates and reveals a diagnostics bundle for you to attach, and opens a pre-filled GitHub issue — OmniWM never sees your GitHub login.&lt;/p&gt; 
&lt;p&gt;Prefer the web? The &lt;a href=&quot;https://github.com/BarutSRB/OmniWM/issues/new/choose&quot;&gt;GitHub issue form&lt;/a&gt; works too; please include your OmniWM and macOS versions there.&lt;/p&gt; 
&lt;h2&gt;Contributing&lt;/h2&gt; 
&lt;p&gt;Issues and pull requests are welcome on &lt;a href=&quot;https://github.com/BarutSRB/OmniWM&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Start with &lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/CONTRIBUTING.md&quot;&gt;CONTRIBUTING.md&lt;/a&gt; for the actual project guidelines, expectations, and preferred direction.&lt;/p&gt; 
&lt;p&gt;For deeper technical context, the docs pages that back the documentation site are here:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/ARCHITECTURE.md&quot;&gt;Architecture Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/IPC-CLI.md&quot;&gt;IPC &amp;amp; CLI Reference&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/docs/CONTRIBUTING.md&quot;&gt;Contribution Docs&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;OmniWM is licensed under the &lt;a href=&quot;https://raw.githubusercontent.com/BarutSRB/OmniWM/main/LICENSE&quot;&gt;GNU General Public License v2.0-only&lt;/a&gt;. Copyright (C) 2026 BarutSRB — &lt;a href=&quot;https://github.com/BarutSRB/OmniWM&quot;&gt;https://github.com/BarutSRB/OmniWM&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Every source file carries an SPDX license header. Forks and redistributions must retain these notices and the &lt;code&gt;LICENSE&lt;/code&gt; file, and remain GPL-2.0 with source available.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/04cd59cd97dd6c550bf197d00469f1cd8de7862709a72ecd005420c7d0b9fdab/BarutSRB/OmniWM" medium="image" />
      
    </item>
    
    <item>
      <title>nikitabobko/AeroSpace</title>
      <link>https://github.com/nikitabobko/AeroSpace</link>
      <description>&lt;p&gt;AeroSpace is an i3-like tiling window manager for macOS&lt;/p&gt;&lt;hr&gt;&lt;h1&gt;AeroSpace Beta &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/actions/workflows/build.yml&quot;&gt;&lt;img src=&quot;https://github.com/nikitabobko/AeroSpace/actions/workflows/build.yml/badge.svg?branch=main&quot; alt=&quot;Build&quot; /&gt;&lt;/a&gt;&lt;/h1&gt; 
&lt;img src=&quot;https://raw.githubusercontent.com/nikitabobko/AeroSpace/main/resources/Assets.xcassets/AppIcon.appiconset/icon.png&quot; width=&quot;40%&quot; align=&quot;right&quot; /&gt; 
&lt;p&gt;AeroSpace is an i3-like tiling window manager for macOS&lt;/p&gt; 
&lt;p&gt;Videos:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=UOl7ErqWbrk&quot;&gt;YouTube 91 sec Demo&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-FoWClVHG5g&quot;&gt;YouTube Guide by Josean Martinez&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Docs:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide&quot;&gt;AeroSpace Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/commands&quot;&gt;AeroSpace Commands&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/goodies&quot;&gt;AeroSpace Goodies&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Key features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Tiling window manager based on a &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#tree&quot;&gt;tree paradigm&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://i3wm.org/&quot;&gt;i3&lt;/a&gt; inspired&lt;/li&gt; 
 &lt;li&gt;Fast workspaces switching without animations and without the necessity to disable SIP&lt;/li&gt; 
 &lt;li&gt;AeroSpace employs its &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#emulation-of-virtual-workspaces&quot;&gt;own emulation of virtual workspaces&lt;/a&gt; instead of relying on native macOS Spaces due to &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#emulation-of-virtual-workspaces&quot;&gt;their considerable limitations&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Plain text configuration (dotfiles friendly). See: &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#default-config&quot;&gt;default-config.toml&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;CLI first (manpages and shell completion included)&lt;/li&gt; 
 &lt;li&gt;Doesn&#39;t require disabling SIP (System Integrity Protection)&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#multiple-monitors&quot;&gt;Proper multi-monitor support&lt;/a&gt; (i3-like paradigm)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;p&gt;Install via &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; to get autoupdates (Preferred)&lt;/p&gt; 
&lt;pre&gt;&lt;code&gt;brew install --cask nikitabobko/tap/aerospace
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;In multi-monitor setup please make sure that monitors &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#proper-monitor-arrangement&quot;&gt;are properly arranged&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Other installation options: &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#installation&quot;&gt;https://nikitabobko.github.io/AeroSpace/guide#installation&lt;/a&gt;&lt;/p&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;By using AeroSpace, you acknowledge that it&#39;s not &lt;a href=&quot;https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution&quot;&gt;notarized&lt;/a&gt;.&lt;/p&gt; 
 &lt;p&gt;Notarization is a &quot;security&quot; feature by Apple. You send binaries to Apple, and they either approve them or not. In reality, notarization is about building binaries the way Apple likes it.&lt;/p&gt; 
 &lt;p&gt;I don&#39;t have anything against notarization as a concept. I specifically don&#39;t like the way Apple does notarization. I don&#39;t have time to deal with Apple.&lt;/p&gt; 
 &lt;p&gt;&lt;a href=&quot;https://github.com/nikitabobko/homebrew-tap/raw/main/Casks/aerospace.rb&quot;&gt;Homebrew installation script&lt;/a&gt; is configured to automatically delete &lt;code&gt;com.apple.quarantine&lt;/code&gt; attribute, that&#39;s why the app should work out of the box, without any warnings that &quot;Apple cannot check AeroSpace for malicious software&quot;&lt;/p&gt; 
&lt;/div&gt; 
&lt;h2&gt;Community, discussions, issues&lt;/h2&gt; 
&lt;p&gt;AeroSpace project doesn&#39;t accept Issues directly - we ask you to create a &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions&quot;&gt;Discussion&lt;/a&gt; first. Please read &lt;a href=&quot;https://raw.githubusercontent.com/nikitabobko/AeroSpace/main/CONTRIBUTING.md&quot;&gt;CONTRIBUTING.md&lt;/a&gt; for more details.&lt;/p&gt; 
&lt;p&gt;Community discussions happen at GitHub Discussions. There you can discuss bugs, propose new features, ask your questions, show off your setup, or just chat.&lt;/p&gt; 
&lt;p&gt;There are 7 channels:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions&quot;&gt;#all&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions.atom?discussions_q=sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;. Feed with all discussions.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/announcements&quot;&gt;#announcements&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/announcements.atom?discussions_q=category%3Aannouncements+sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;. Only maintainers can post here. Highly moderated traffic.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/announcements-releases&quot;&gt;#announcements-releases&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/announcements-releases.atom?discussions_q=category%3Aannouncements-releases+sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;. Announcements about non-patch releases. Only maintainers can post here.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/feature-ideas&quot;&gt;#feature-ideas&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/feature-ideas.atom?discussions_q=category%3Afeature-ideas+sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/general&quot;&gt;#general&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/general.atom?discussions_q=sort%3Adate_created+category%3Ageneral&quot;&gt;RSS&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/potential-bugs&quot;&gt;#potential-bugs&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/potential-bugs.atom?discussions_q=category%3Apotential-bugs+sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;. If you think that you have encountered a bug, you can discuss your bugs here.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/questions-and-answers&quot;&gt;#questions-and-answers&lt;/a&gt;. &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/discussions/categories/questions-and-answers.atom?discussions_q=category%3Aquestions-and-answers+sort%3Adate_created&quot;&gt;RSS&lt;/a&gt;. Everyone is welcome to ask questions. Everyone is encouraged to answer other people&#39;s questions.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Project status&lt;/h2&gt; 
&lt;p&gt;Public Beta. AeroSpace can be used as a daily driver, but expect breaking changes until 1.0 is reached.&lt;/p&gt; 
&lt;p&gt;What stops us from 1.0 release:&lt;/p&gt; 
&lt;ul class=&quot;task-list&quot;&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_0&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_0&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/131&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/131&lt;/a&gt; Performance. Implement thread-per-application to circumvent macOS blocking AX API.&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_1&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_1&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/1215&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/1215&lt;/a&gt; &lt;em&gt;Big refactoring&lt;/em&gt;. Rewrite mutable double-linked core tree data structure to immutable single-linked persistent tree. Important for: stability and potential performance&lt;/label&gt; 
  &lt;ul class=&quot;task-list&quot;&gt; 
   &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_2&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_2&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/1216&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/1216&lt;/a&gt; The big refactoring will help us to fix stability issue that windows may randomly jump to the focused workspace&lt;/label&gt;&lt;/li&gt; 
   &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_3&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_3&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/68&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/68&lt;/a&gt; The big refactoring will help us to support macOS native tabs&lt;/label&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_4&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_4&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/278&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/278&lt;/a&gt; Implement shell-like combinators. Ignore a lot of crazy fuss in the issue, We are most probably going with the minimal approach to only introduce common shell-combinators: &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt; and &lt;code&gt;eval&lt;/code&gt; command to send multiple commands in one go.&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_5&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_5&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/1012&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/1012&lt;/a&gt; Investigate a possibility to use &lt;code&gt;CGEvent.tapCreate&lt;/code&gt; API for global hotkeys&lt;/label&gt; 
  &lt;ul class=&quot;task-list&quot;&gt; 
   &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_6&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_6&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/28&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/28&lt;/a&gt; Maybe it will allow to distinguish left and right modifiers. Maybe not&lt;/label&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Big and important issues which will go after 1.0 release:&lt;/p&gt; 
&lt;ul class=&quot;task-list&quot;&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_7&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_7&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/2&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/2&lt;/a&gt; sticky windows&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_8&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_8&quot;&gt; &lt;a href=&quot;https://github.com/nikitabobko/AeroSpace/issues/260&quot;&gt;https://github.com/nikitabobko/AeroSpace/issues/260&lt;/a&gt; Dynamic TWM&lt;/label&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Development&lt;/h2&gt; 
&lt;p&gt;A notes on how to setup the project, build it, how to run the tests, etc. can be found here: &lt;a href=&quot;https://raw.githubusercontent.com/nikitabobko/AeroSpace/main/dev-docs/development.md&quot;&gt;dev-docs/development.md&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Project values&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Values&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;AeroSpace is targeted at advanced users and developers&lt;/li&gt; 
 &lt;li&gt;Keyboard centric&lt;/li&gt; 
 &lt;li&gt;Breaking changes (configuration files, CLI, behavior) are avoided as much as possible, but it must not let the software stagnate. Thus breaking changes can happen, but with careful considerations and helpful message. &lt;a href=&quot;https://semver.org/&quot;&gt;Semver&lt;/a&gt; major version is bumped in case of a breaking change (It&#39;s all guaranteed once AeroSpace reaches 1.0 version, until then breaking changes just happen)&lt;/li&gt; 
 &lt;li&gt;AeroSpace doesn&#39;t use GUI, unless necessarily 
  &lt;ul&gt; 
   &lt;li&gt;AeroSpace will never provide a GUI for configuration. For advanced users, it&#39;s easier to edit a configuration file in text editor rather than navigating through checkboxes in GUI.&lt;/li&gt; 
   &lt;li&gt;Status menu icon is ok, because visual feedback is needed&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;Provide &lt;em&gt;practical&lt;/em&gt; features. Fancy appearance features are not &lt;em&gt;practical&lt;/em&gt; (e.g. window borders, transparency, animations, etc.)&lt;/li&gt; 
 &lt;li&gt;&quot;dark magic&quot; (aka &quot;private APIs&quot;, &quot;code injections&quot;, etc.) must be avoided as much as possible 
  &lt;ul&gt; 
   &lt;li&gt;Right now, AeroSpace uses only a single private API to get window ID of accessibility object &lt;code&gt;_AXUIElementGetWindow&lt;/code&gt;. Everything else is &lt;a href=&quot;https://developer.apple.com/documentation/applicationservices/axuielement_h&quot;&gt;macOS public accessibility API&lt;/a&gt;.&lt;/li&gt; 
   &lt;li&gt;AeroSpace will never require you to disable SIP (System Integrity Protection).&lt;/li&gt; 
   &lt;li&gt;The goal is to make AeroSpace easily maintainable, and resistant to macOS updates.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Non Values&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Play nicely with existing macOS features. If limitations are imposed then AeroSpace won&#39;t play nicely with existing macOS features (For example, AeroSpace doesn&#39;t acknowledge the existence of macOS Spaces, and it uses &lt;a href=&quot;https://nikitabobko.github.io/AeroSpace/guide#emulation-of-virtual-workspaces&quot;&gt;emulation of its own workspaces&lt;/a&gt;)&lt;/li&gt; 
 &lt;li&gt;Ricing. AeroSpace provides only a very minimal support for ricing - gaps and a few callbacks for integrations with bars. The current maintainer doesn&#39;t care about ricing. Ricing issues are not a priority, and they are mostly ignored. The ricing stance can change only with the appearance of more maintainers.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;macOS compatibility table&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;AeroSpace binary runs on: macOS 13+&lt;/li&gt; 
 &lt;li&gt;AeroSpace debug build from sources is supported on: macOS 14+&lt;/li&gt; 
 &lt;li&gt;AeroSpace release build from sources is supported on: macOS 15+ (Requires Xcode 26+)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Sponsorship&lt;/h2&gt; 
&lt;p&gt;AeroSpace is developed and maintained in my free time. If you find it useful, &lt;a href=&quot;https://github.com/sponsors/nikitabobko#sponsors&quot;&gt;consider sponsoring&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;People who have write access&lt;/h2&gt; 
&lt;p&gt;In alphabetical order:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/mobile-ar&quot;&gt;@mobile-ar&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/nikitabobko&quot;&gt;@nikitabobko&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/rickyz&quot;&gt;@rickyz&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Tip of the day&lt;/h2&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;defaults write -g NSWindowShouldDragOnGesture -bool true
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Now, you can move windows by holding &lt;code&gt;ctrl&lt;/code&gt;+&lt;code&gt;cmd&lt;/code&gt; and dragging any part of the window (not necessarily the window title)&lt;/p&gt; 
&lt;p&gt;Source: &lt;a href=&quot;https://www.reddit.com/r/MacOS/comments/k6hiwk/keyboard_modifier_to_simplify_click_drag_of/&quot;&gt;reddit&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Related projects&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/ianyh/Amethyst&quot;&gt;Amethyst&lt;/a&gt; - tiling window manager à la xmonad&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/jurplel/InstantSpaceSwitcher&quot;&gt;InstantSpaceSwitcher&lt;/a&gt; - Instant space switching by synthesizing trackpad gesture with an artificially high velocity&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/koekeishiya/yabai&quot;&gt;yabai&lt;/a&gt; - a tiling window manager for macOS based on binary space partitioning&lt;/li&gt; 
&lt;/ul&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/fbf459f8cca8e08093ead2a630f3cb6e446e5f7da0631d73d8fd5bfad55c38f3/nikitabobko/AeroSpace" medium="image" />
      
    </item>
    
    <item>
      <title>realm/SwiftLint</title>
      <link>https://github.com/realm/SwiftLint</link>
      <description>&lt;p&gt;A tool to enforce Swift style and conventions.&lt;/p&gt;&lt;hr&gt;&lt;h1&gt;SwiftLint&lt;/h1&gt; 
&lt;p&gt;A tool to enforce Swift style and conventions, loosely based on the now archived &lt;a href=&quot;https://github.com/github/swift-style-guide&quot;&gt;GitHub Swift Style Guide&lt;/a&gt;. SwiftLint enforces the style guide rules that are generally accepted by the Swift community. These rules are well described in popular style guides like &lt;a href=&quot;https://github.com/kodecocodes/swift-style-guide&quot;&gt;Kodeco&#39;s Swift Style Guide&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;SwiftLint rules are predominantly based on &lt;a href=&quot;https://github.com/swiftlang/swift-syntax&quot;&gt;SwiftSyntax&lt;/a&gt;. Some rules still hook into &lt;a href=&quot;http://clang.llvm.org&quot;&gt;Clang&lt;/a&gt; and &lt;a href=&quot;http://www.jpsim.com/uncovering-sourcekit&quot;&gt;SourceKit&lt;/a&gt; to access type information.&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/realm/SwiftLint&quot;&gt;&lt;img src=&quot;https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Frealm%2FSwiftLint%2Fbadge%3Ftype%3Dswift-versions&quot; alt=&quot;Supported Swift Versions&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://swiftpackageindex.com/realm/SwiftLint&quot;&gt;&lt;img src=&quot;https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Frealm%2FSwiftLint%2Fbadge%3Ftype%3Dplatforms&quot; alt=&quot;Supported Platforms&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://buildkite.com/swiftlint/swiftlint&quot;&gt;&lt;img src=&quot;https://badge.buildkite.com/e2a5bc32c347e76e2793e4c5764a5f42bcd42bbe32f79c3a53.svg?branch=main&quot; alt=&quot;Buildkite Build Status&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/assets/screenshot.png&quot; alt=&quot;SwiftLint violations highlighted in the Xcode editor&quot; /&gt;&lt;/p&gt; 
&lt;p&gt;This project adheres to the &lt;a href=&quot;https://realm.io/conduct&quot;&gt;Contributor Covenant Code of Conduct&lt;/a&gt;. By participating, you are expected to uphold this code.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;Switch Language: &lt;a href=&quot;https://github.com/realm/SwiftLint/raw/main/README_CN.md&quot;&gt;中文&lt;/a&gt;, &lt;a href=&quot;https://github.com/realm/SwiftLint/raw/main/README_KR.md&quot;&gt;한국어&lt;/a&gt;&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Video Introduction&lt;/h2&gt; 
&lt;p&gt;To get a high-level overview of SwiftLint, we encourage you to watch this presentation recorded January 9th, 2017 by JP Simard (transcript provided):&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://youtu.be/9Z1nTMTejqU&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/assets/presentation.svg?sanitize=true&quot; alt=&quot;Presentation&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;h3&gt;&lt;a href=&quot;https://github.com/apple/swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;SwiftLint can be used as a &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#swift-package-command-plugin&quot;&gt;command plugin&lt;/a&gt; or a &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#build-tool-plugins&quot;&gt;build tool plugin&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Add&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.package(url: &quot;https://github.com/SimplyDanny/SwiftLintPlugins&quot;, from: &quot;&amp;lt;version&amp;gt;&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;to your &lt;code&gt;Package.swift&lt;/code&gt; file to consume the latest release of SwiftLint automatically or pin the dependency to a specific version:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.package(url: &quot;https://github.com/SimplyDanny/SwiftLintPlugins&quot;, exact: &quot;&amp;lt;version&amp;gt;&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Therein, replace &lt;code&gt;&amp;lt;version&amp;gt;&lt;/code&gt; with the desired minimum or exact version.&lt;/p&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;Consuming the plugins directly from the SwiftLint repository comes with several drawbacks. To avoid them and reduce the overhead imposed, it&#39;s highly recommended to consume the plugins from the dedicated &lt;a href=&quot;https://github.com/SimplyDanny/SwiftLintPlugins&quot;&gt;SwiftLintPlugins repository&lt;/a&gt;, even though plugins from the SwiftLint repository are also absolutely functional. If the plugins from SwiftLint are preferred, just use the URL &lt;code&gt;https://github.com/realm/SwiftLint&lt;/code&gt; in the package declarations above.&lt;/p&gt; 
 &lt;p&gt;However, &lt;a href=&quot;https://github.com/SimplyDanny/SwiftLintPlugins&quot;&gt;SwiftLintPlugins&lt;/a&gt; facilitates plugin adoption massively. It lists some of the reasons that drive the plugins as provided by SwiftLint itself very troublesome. Since the plugin code and the releases are kept in sync, there is no difference in functionality between the two, but you spare yourself a lot of time and trouble using the dedicated plugins repository.&lt;/p&gt; 
 &lt;p&gt;This document assumes you&#39;re relying on SwiftLintPlugins.&lt;/p&gt; 
&lt;/div&gt; 
&lt;h3&gt;&lt;a href=&quot;https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app&quot;&gt;Xcode Package Dependency&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;Use the following link to add SwiftLint as a Package Dependency to an Xcode project:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;https://github.com/SimplyDanny/SwiftLintPlugins
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;&lt;a href=&quot;http://brew.sh&quot;&gt;Homebrew&lt;/a&gt;&lt;/h3&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install swiftlint
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;&lt;a href=&quot;https://cocoapods.org&quot;&gt;CocoaPods&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;Add the following to your &lt;code&gt;Podfile&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;pod &#39;SwiftLint&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This will download the SwiftLint binaries and dependencies in &lt;code&gt;Pods/&lt;/code&gt; during your next &lt;code&gt;pod install&lt;/code&gt; execution and will allow you to invoke it via &lt;code&gt;${PODS_ROOT}/SwiftLint/swiftlint&lt;/code&gt; in your Script Build Phases.&lt;/p&gt; 
&lt;p&gt;Installing via Cocoapods also enables pinning to a specific version of SwiftLint rather than simply the latest (which is the case with &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#homebrew&quot;&gt;Homebrew&lt;/a&gt;).&lt;/p&gt; 
&lt;p&gt;Note that this will add the SwiftLint binaries, its dependencies&#39; binaries, and the Swift binary library distribution to the &lt;code&gt;Pods/&lt;/code&gt; directory, so checking in this directory to SCM such as Git is discouraged.&lt;/p&gt; 
&lt;h3&gt;&lt;a href=&quot;https://github.com/yonaskolb/mint&quot;&gt;Mint&lt;/a&gt;&lt;/h3&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mint install realm/SwiftLint
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;&lt;a href=&quot;https://bazel.build&quot;&gt;Bazel&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;Put this in your &lt;code&gt;MODULE.bazel&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bzl&quot;&gt;bazel_dep(name = &quot;swiftlint&quot;, version = &quot;0.52.4&quot;, repo_name = &quot;SwiftLint&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Or put this in your &lt;code&gt;WORKSPACE&lt;/code&gt;:&lt;/p&gt; 
&lt;details&gt; 
 &lt;summary&gt;WORKSPACE&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-bzl&quot;&gt;load(&quot;@bazel_tools//tools/build_defs/repo:http.bzl&quot;, &quot;http_archive&quot;)

http_archive(
    name = &quot;build_bazel_rules_apple&quot;,
    sha256 = &quot;390841dd5f8a85fc25776684f4793d56e21b098dfd7243cd145b9831e6ef8be6&quot;,
    url = &quot;https://github.com/bazelbuild/rules_apple/releases/download/2.4.1/rules_apple.2.4.1.tar.gz&quot;,
)

load(
    &quot;@build_bazel_rules_apple//apple:repositories.bzl&quot;,
    &quot;apple_rules_dependencies&quot;,
)

apple_rules_dependencies()

load(
    &quot;@build_bazel_rules_swift//swift:repositories.bzl&quot;,
    &quot;swift_rules_dependencies&quot;,
)

swift_rules_dependencies()

load(
    &quot;@build_bazel_rules_swift//swift:extras.bzl&quot;,
    &quot;swift_rules_extra_dependencies&quot;,
)

swift_rules_extra_dependencies()

http_archive(
    name = &quot;SwiftLint&quot;,
    sha256 = &quot;c6ea58b9c72082cdc1ada4a2d48273ecc355896ed72204cedcc586b6ccb8aca6&quot;,
    url = &quot;https://github.com/realm/SwiftLint/releases/download/0.52.4/bazel.tar.gz&quot;,
)

load(&quot;@SwiftLint//bazel:repos.bzl&quot;, &quot;swiftlint_repos&quot;)

swiftlint_repos()

load(&quot;@SwiftLint//bazel:deps.bzl&quot;, &quot;swiftlint_deps&quot;)

swiftlint_deps()
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;p&gt;Then you can run SwiftLint in the current directory with this command:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;bazel run -c opt @SwiftLint//:swiftlint
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Pre-Built Package&lt;/h3&gt; 
&lt;p&gt;Download &lt;code&gt;SwiftLint.pkg&lt;/code&gt; from the &lt;a href=&quot;https://github.com/realm/SwiftLint/releases/latest&quot;&gt;latest GitHub release&lt;/a&gt; and run it.&lt;/p&gt; 
&lt;h3&gt;From Source&lt;/h3&gt; 
&lt;p&gt;Make sure the build tool &lt;a href=&quot;https://bazel.build&quot;&gt;Bazel&lt;/a&gt; and a recent &lt;a href=&quot;https://www.swift.org/download/&quot;&gt;Swift toolchain&lt;/a&gt; are installed and all tools are discoverable in your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;To build SwiftLint, clone this repository and run &lt;code&gt;make install&lt;/code&gt;.&lt;/p&gt; 
&lt;h2&gt;Setup&lt;/h2&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-report mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Important&lt;/p&gt;
 &lt;p&gt;While it may seem intuitive to run SwiftLint before compiling Swift source files to exit a build early when there are lint violations, it is important to understand that SwiftLint is designed to analyze valid source code that is compilable. Non-compiling code can very easily lead to unexpected and confusing results, especially when executing with &lt;code&gt;--fix&lt;/code&gt;/&lt;code&gt;--autocorrect&lt;/code&gt; command line arguments.&lt;/p&gt; 
&lt;/div&gt; 
&lt;h3&gt;Build Tool Plugins&lt;/h3&gt; 
&lt;p&gt;SwiftLint can be used as a build tool plugin for both &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#swift-package-projects&quot;&gt;Swift Package projects&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#xcode-projects&quot;&gt;Xcode projects&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;The build tool plugin determines the SwiftLint working directory by locating the topmost config file within the package/project directory. If a config file is not found therein, the package/project directory is used as the working directory.&lt;/p&gt; 
&lt;p&gt;The plugin throws an error when it is unable to resolve the SwiftLint working directory. For example, this will occur in Xcode projects where the target&#39;s Swift files are not located within the project directory.&lt;/p&gt; 
&lt;p&gt;To maximize compatibility with the plugin, avoid project structures that require the use of the &lt;code&gt;--config&lt;/code&gt; option.&lt;/p&gt; 
&lt;h3&gt;Swift Package Projects&lt;/h3&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;Requires installing via &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;.&lt;/p&gt; 
&lt;/div&gt; 
&lt;p&gt;Build tool plugins run when building each target. When a project has multiple targets, the plugin must be added to the desired targets individually.&lt;/p&gt; 
&lt;p&gt;To do this, add the plugin to the target(s) to be linted as follows:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.target(
    ...
    plugins: [.plugin(name: &quot;SwiftLintBuildToolPlugin&quot;, package: &quot;SwiftLintPlugins&quot;)]
),
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Swift Package Command Plugin&lt;/h3&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;Requires installing via &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;.&lt;/p&gt; 
&lt;/div&gt; 
&lt;p&gt;The command plugin enables running SwiftLint from the command line as follows:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;swift package plugin swiftlint
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Xcode Projects&lt;/h3&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;Requires installing via &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#xcode-package-dependency&quot;&gt;Xcode Package Dependency&lt;/a&gt;.&lt;/p&gt; 
&lt;/div&gt; 
&lt;p&gt;Build tool plugins run as a build phase of each target. When a project has multiple targets, the plugin must be added to the desired targets individually.&lt;/p&gt; 
&lt;p&gt;To do this, add the &lt;code&gt;SwiftLintBuildToolPlugin&lt;/code&gt; to the &lt;code&gt;Run Build Tool Plug-ins&lt;/code&gt; phase of the &lt;code&gt;Build Phases&lt;/code&gt; for the target(s) to be linted.&lt;/p&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Tip&lt;/p&gt;
 &lt;p&gt;When using the plugin for the first time, be sure to trust and enable it when prompted. If a macros build warning exists, select it to trust and enable the macros as well.&lt;/p&gt; 
&lt;/div&gt; 
&lt;p&gt;For unattended use (e.g. on CI), package plugin and macro validations can be disabled with either of the following:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;Using &lt;code&gt;xcodebuild&lt;/code&gt; options:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;-skipPackagePluginValidation
-skipMacroValidation
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Setting Xcode defaults:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES
defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-report mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Important&lt;/p&gt;
 &lt;p&gt;The unattended use options bypass Xcode&#39;s validation dialogs and implicitly trust all plugins and macros, which has security implications.&lt;/p&gt; 
&lt;/div&gt; 
&lt;h4&gt;Unexpected Xcode Project Structures&lt;/h4&gt; 
&lt;p&gt;Project structures where SwiftLint&#39;s configuration file is located outside of the package/project directory are not directly supported by the build tool plugin. This is because it isn&#39;t possible to pass arguments to build tool plugins (e.g., passing the config file path).&lt;/p&gt; 
&lt;p&gt;If your project structure doesn&#39;t work directly with the build tool plugin, please consider one of the following options:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;To use a config file located outside the package/project directory, a config file may be added to that directory specifying a parent config path to the other config file, e.g., &lt;code&gt;parent_config: path/to/.swiftlint.yml&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;You can also consider the use of a &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#xcode-run-script-build-phase&quot;&gt;Run Script Build Phase&lt;/a&gt; in place of the build tool plugin.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Xcode Run Script Build Phase&lt;/h3&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;Based upon the installation method used, the shell command syntax in the Run Script Build Phase may be different or additional configuration could be required. Refer to the &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#installation&quot;&gt;installation&lt;/a&gt; instructions for more information.&lt;/p&gt; 
&lt;/div&gt; 
&lt;p&gt;If the build tool plugin does not work for your project setup or when additional custom setup is required, SwiftLint can be added as a Run Script Build Phase. This is useful when a project setup relies on the &lt;code&gt;--config&lt;/code&gt; SwiftLint option; or to lint all targets together in a single &lt;code&gt;swiftlint&lt;/code&gt; invocation. File inclusions and exclusions can be configured in the &lt;a href=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/#configuration&quot;&gt;&lt;code&gt;.swiftlint.yml&lt;/code&gt; configuration&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;To do this, add a custom script to a &lt;code&gt;Run Script&lt;/code&gt; phase of the &lt;code&gt;Build Phases&lt;/code&gt; of the primary app target, after the &lt;code&gt;Compile Sources&lt;/code&gt; phase. Use the following script implementation:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;if command -v swiftlint &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
then
    swiftlint
else
    echo &quot;warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#installation for installation instructions.&quot;
fi
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If you&#39;re using the SwiftLintPlugin in a Swift package, you may refer to the &lt;code&gt;swiftlint&lt;/code&gt; executable in the following way:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SWIFT_PACKAGE_DIR=&quot;${SWIFT_PACKAGE_DIR:-${BUILD_DIR%Build/*}SourcePackages}&quot;
SWIFTLINT_CMD=&quot;$SWIFT_PACKAGE_DIR/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/macos/swiftlint&quot;

if test -f &quot;$SWIFTLINT_CMD&quot; 2&amp;gt;&amp;amp;1
then
    &quot;$SWIFTLINT_CMD&quot;
else
    echo &quot;warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#xcode-run-script-build-phase for installation instructions.&quot;
fi
&lt;/code&gt;&lt;/pre&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;The &lt;code&gt;SWIFTLINT_CMD&lt;/code&gt; path uses the default Xcode configuration and has been tested on Xcode 15/16. In case of another configuration (e.g. a custom Swift package path), please adapt the values accordingly. If you run &lt;code&gt;xcodebuild&lt;/code&gt; with &lt;code&gt;-clonedSourcePackagesDirPath&lt;/code&gt;, set &lt;code&gt;SWIFT_PACKAGE_DIR&lt;/code&gt; to &lt;code&gt;&amp;lt;that path&amp;gt;&lt;/code&gt; before running the script.&lt;/p&gt; 
&lt;/div&gt; 
&lt;!-- markdownlint-disable MD028 --&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Tip&lt;/p&gt;
 &lt;p&gt;Uncheck &lt;code&gt;Based on dependency analysis&lt;/code&gt; to run &lt;code&gt;swiftlint&lt;/code&gt; on all incremental builds, suppressing the unspecified outputs warning.&lt;/p&gt; 
&lt;/div&gt; 
&lt;h4&gt;Consideration for Xcode 15.0&lt;/h4&gt; 
&lt;p&gt;Xcode 15 made a significant change by setting the default value of the &lt;code&gt;ENABLE_USER_SCRIPT_SANDBOXING&lt;/code&gt; build setting from &lt;code&gt;NO&lt;/code&gt; to &lt;code&gt;YES&lt;/code&gt;. As a result, SwiftLint encounters an error related to missing file permissions, which typically manifests as &lt;code&gt;error: Sandbox: swiftlint(19427) deny(1) file-read-data.&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;To resolve this issue, it is necessary to manually set the &lt;code&gt;ENABLE_USER_SCRIPT_SANDBOXING&lt;/code&gt; setting to &lt;code&gt;NO&lt;/code&gt; for the specific target that SwiftLint is being configured for.&lt;/p&gt; 
&lt;h4&gt;Consideration for Apple Silicon&lt;/h4&gt; 
&lt;p&gt;If you installed SwiftLint via Homebrew on Apple Silicon, you might experience this warning:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;That is because Homebrew on Apple Silicon installs the binaries into the &lt;code&gt;/opt/homebrew/bin&lt;/code&gt; folder by default. To instruct Xcode where to find SwiftLint, you can either add &lt;code&gt;/opt/homebrew/bin&lt;/code&gt; to the &lt;code&gt;PATH&lt;/code&gt; environment variable in your build phase:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;if [[ &quot;$(uname -m)&quot; == arm64 ]]
then
    export PATH=&quot;/opt/homebrew/bin:$PATH&quot;
fi

if command -v swiftlint &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
then
    swiftlint
else
    echo &quot;warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#installation for installation instructions.&quot;
fi
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;or you can create a symbolic link in &lt;code&gt;/usr/local/bin&lt;/code&gt; pointing to the actual binary:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint
&lt;/code&gt;&lt;/pre&gt; 
&lt;h4&gt;Additional Considerations&lt;/h4&gt; 
&lt;p&gt;If you wish to fix violations as well, your script could run &lt;code&gt;swiftlint --fix &amp;amp;&amp;amp; swiftlint&lt;/code&gt; instead of just &lt;code&gt;swiftlint&lt;/code&gt;. This will mean that all correctable violations are fixed while ensuring warnings show up in your project for remaining violations.&lt;/p&gt; 
&lt;p&gt;If you&#39;ve installed SwiftLint via CocoaPods the script should look like this:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&quot;${PODS_ROOT}/SwiftLint/swiftlint&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Visual Studio Code&lt;/h3&gt; 
&lt;p&gt;To integrate SwiftLint with &lt;a href=&quot;https://code.visualstudio.com&quot;&gt;Visual Studio Code&lt;/a&gt;, install the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=vknabel.vscode-swiftlint&quot;&gt;&lt;code&gt;vscode-swiftlint&lt;/code&gt;&lt;/a&gt; extension from the marketplace.&lt;/p&gt; 
&lt;h3&gt;Fastlane&lt;/h3&gt; 
&lt;p&gt;You can use the official &lt;a href=&quot;https://docs.fastlane.tools/actions/swiftlint&quot;&gt;&lt;code&gt;swiftlint&lt;/code&gt; fastlane action&lt;/a&gt; to run SwiftLint as part of your fastlane process.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;swiftlint(
    mode: :lint,                            # SwiftLint mode: :lint (default) or :autocorrect
    executable: &quot;Pods/SwiftLint/swiftlint&quot;, # The SwiftLint binary path (optional). Important if you&#39;ve installed it via CocoaPods
    path: &quot;/path/to/lint&quot;,                  # Specify path to lint (optional)
    output_file: &quot;swiftlint.result.json&quot;,   # The path of the output file (optional)
    reporter: &quot;json&quot;,                       # The custom reporter to use (optional)
    config_file: &quot;.swiftlint-ci.yml&quot;,       # The path of the configuration file (optional)
    files: [                                # List of files to process (optional)
        &quot;AppDelegate.swift&quot;,
        &quot;path/to/project/Model.swift&quot;
    ],
    ignore_exit_status: true,               # Allow fastlane to continue even if SwiftLint returns a non-zero exit status (Default: false)
    quiet: true,                            # Don&#39;t print status logs like &#39;Linting &#39; &amp;amp; &#39;Done linting&#39; (Default: false)
    strict: true                            # Fail on warnings? (Default: false)
)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Docker&lt;/h3&gt; 
&lt;p&gt;SwiftLint is also available as a &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; image using &lt;code&gt;Ubuntu&lt;/code&gt;. So just the first time you need to pull the docker image using the next command:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker pull ghcr.io/realm/swiftlint:latest
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Then following times, you just run &lt;code&gt;swiftlint&lt;/code&gt; inside of the docker like:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This will execute &lt;code&gt;swiftlint&lt;/code&gt; in the folder where you are right now (&lt;code&gt;pwd&lt;/code&gt;), showing an output like:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest
Linting Swift files in current working directory
Linting &#39;RuleDocumentation.swift&#39; (1/490)
...
Linting &#39;YamlSwiftLintTests.swift&#39; (490/490)
Done linting! Found 0 violations, 0 serious in 490 files.
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Here you have more documentation about the usage of &lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker Images&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;MegaLinter&lt;/h3&gt; 
&lt;p&gt;SwiftLint is also embedded in &lt;a href=&quot;https://megalinter.io&quot;&gt;MegaLinter&lt;/a&gt;, an open-source aggregator of linters for CI. See its &lt;a href=&quot;https://megalinter.io/latest/descriptors/swift_swiftlint/&quot;&gt;SwiftLint documentation&lt;/a&gt; for setup instructions.&lt;/p&gt; 
&lt;h2&gt;Command Line Usage&lt;/h2&gt; 
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;$ swiftlint help
OVERVIEW: A tool to enforce Swift style and conventions.

USAGE: swiftlint &amp;lt;subcommand&amp;gt;

OPTIONS:
  --version               Show the version.
  -h, --help              Show help information.

SUBCOMMANDS:
  analyze                 Run analysis rules
  docs                    Open SwiftLint documentation website in the default web browser
  generate-docs           Generates markdown documentation for selected group of rules
  lint (default)          Print lint warnings and errors
  baseline                Operations on existing baselines
  reporters               Display the list of reporters and their identifiers
  rules                   Display the list of rules and their identifiers
  version                 Display the current version of SwiftLint

  See &#39;swiftlint help &amp;lt;subcommand&amp;gt;&#39; for detailed help.
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Run &lt;code&gt;swiftlint&lt;/code&gt; in the directory containing the Swift files to lint. Directories will be searched recursively.&lt;/p&gt; 
&lt;p&gt;To specify a list of files when using &lt;code&gt;lint&lt;/code&gt; or &lt;code&gt;analyze&lt;/code&gt; (like the list of files modified by Xcode specified by the &lt;a href=&quot;https://github.com/norio-nomura/ExtraBuildPhase&quot;&gt;&lt;code&gt;ExtraBuildPhase&lt;/code&gt;&lt;/a&gt; Xcode plugin, or modified files in the working tree based on &lt;code&gt;git ls-files -m&lt;/code&gt;), you can do so by passing the option &lt;code&gt;--use-script-input-files&lt;/code&gt; and setting the following instance variables: &lt;code&gt;SCRIPT_INPUT_FILE_COUNT&lt;/code&gt; and &lt;code&gt;SCRIPT_INPUT_FILE_0&lt;/code&gt;, &lt;code&gt;SCRIPT_INPUT_FILE_1&lt;/code&gt;, ..., &lt;code&gt;SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}&lt;/code&gt;. Similarly, files can be read from file lists by passing the option &lt;code&gt;--use-script-input-file-lists&lt;/code&gt; and setting the following instance variables: &lt;code&gt;SCRIPT_INPUT_FILE_LIST_COUNT&lt;/code&gt; and &lt;code&gt;SCRIPT_INPUT_FILE_LIST_0&lt;/code&gt;, &lt;code&gt;SCRIPT_INPUT_FILE_LIST_1&lt;/code&gt;, ..., &lt;code&gt;SCRIPT_INPUT_FILE_LIST_{SCRIPT_INPUT_FILE_LIST_COUNT - 1}&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;These are same environment variables set for input files to &lt;a href=&quot;http://indiestack.com/2014/12/speeding-up-custom-script-phases/&quot;&gt;custom Xcode script phases&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Working With Multiple Swift Versions&lt;/h2&gt; 
&lt;p&gt;SwiftLint hooks into SourceKit so it continues working even as Swift evolves!&lt;/p&gt; 
&lt;p&gt;This also keeps SwiftLint lean, as it doesn&#39;t need to ship with a full Swift compiler, it just communicates with the official one you already have installed on your machine.&lt;/p&gt; 
&lt;p&gt;You should always run SwiftLint with the same toolchain you use to compile your code.&lt;/p&gt; 
&lt;p&gt;You may want to override SwiftLint&#39;s default Swift toolchain if you have multiple toolchains or Xcodes installed.&lt;/p&gt; 
&lt;p&gt;Here&#39;s the order in which SwiftLint determines which Swift toolchain to use:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;$XCODE_DEFAULT_TOOLCHAIN_OVERRIDE&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;$TOOLCHAIN_DIR&lt;/code&gt; or &lt;code&gt;$TOOLCHAINS&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;xcrun -find swift&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;~/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;~/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;code&gt;sourcekitd.framework&lt;/code&gt; is expected to be found in the &lt;code&gt;usr/lib/&lt;/code&gt; subdirectory of the value passed in the paths above.&lt;/p&gt; 
&lt;p&gt;You may also set the &lt;code&gt;TOOLCHAINS&lt;/code&gt; environment variable to the reverse-DNS notation that identifies a Swift toolchain version:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint --fix
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;On Linux, SourceKit is expected to be located in &lt;code&gt;/usr/lib/libsourcekitdInProc.so&lt;/code&gt; or specified by the &lt;code&gt;LINUX_SOURCEKIT_LIB_PATH&lt;/code&gt; environment variable.&lt;/p&gt; 
&lt;h2&gt;Git &lt;code&gt;pre-commit&lt;/code&gt; Hook&lt;/h2&gt; 
&lt;p&gt;SwiftLint can be run as a &lt;a href=&quot;https://pre-commit.com/&quot;&gt;pre-commit&lt;/a&gt; hook. Once &lt;a href=&quot;https://pre-commit.com/#install&quot;&gt;installed&lt;/a&gt;, add this to the &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; in the root of your repository:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;repos:
  - repo: https://github.com/realm/SwiftLint
    rev: 0.57.1
    hooks:
      - id: swiftlint
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Adjust &lt;code&gt;rev&lt;/code&gt; to the SwiftLint version of your choice. &lt;code&gt;pre-commit autoupdate&lt;/code&gt; can be used to update to the current version.&lt;/p&gt; 
&lt;p&gt;SwiftLint can be configured using &lt;code&gt;entry&lt;/code&gt; to apply fixes and fail on errors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- repo: https://github.com/realm/SwiftLint
  rev: 0.57.1
  hooks:
    - id: swiftlint
      entry: swiftlint --fix --strict
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Rules&lt;/h2&gt; 
&lt;p&gt;Over 200 rules are included in SwiftLint and the Swift community (that&#39;s you!) continues to contribute more over time. &lt;a href=&quot;https://github.com/realm/SwiftLint/raw/main/CONTRIBUTING.md&quot;&gt;Pull requests&lt;/a&gt; are encouraged.&lt;/p&gt; 
&lt;p&gt;You can find an updated list of rules and more information about them in the &lt;a href=&quot;https://realm.github.io/SwiftLint/rule-directory.html&quot;&gt;Rule Directory&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;You can also check the &lt;a href=&quot;https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintBuiltInRules/Rules&quot;&gt;Source/SwiftLintBuiltInRules/Rules&lt;/a&gt; directory to see their implementation.&lt;/p&gt; 
&lt;h3&gt;Opt-In Rules&lt;/h3&gt; 
&lt;p&gt;&lt;code&gt;opt_in_rules&lt;/code&gt; are disabled by default (i.e., you have to explicitly enable them in your configuration file).&lt;/p&gt; 
&lt;p&gt;Guidelines on when to mark a rule as opt-in:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;A rule that can have many false positives (e.g. &lt;code&gt;empty_count&lt;/code&gt;)&lt;/li&gt; 
 &lt;li&gt;A rule that is too slow&lt;/li&gt; 
 &lt;li&gt;A rule that is not general consensus or is only useful in some cases (e.g. &lt;code&gt;force_unwrapping&lt;/code&gt;)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Disable rules in code&lt;/h3&gt; 
&lt;p&gt;Rules can be disabled with a comment inside a source file with the following format:&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;// swiftlint:disable &amp;lt;rule1&amp;gt; [&amp;lt;rule2&amp;gt; &amp;lt;rule3&amp;gt;...]&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;The rules will be disabled until the end of the file or until the linter sees a matching enable comment:&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;// swiftlint:enable &amp;lt;rule1&amp;gt; [&amp;lt;rule2&amp;gt; &amp;lt;rule3&amp;gt;...]&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// swiftlint:disable colon
let noWarning :String = &quot;&quot; // No warning about colons immediately after variable names.
// swiftlint:enable colon
let hasWarning :String = &quot;&quot; // Warning generated about colons immediately after variable names.
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Including the &lt;code&gt;all&lt;/code&gt; keyword will disable all rules until the linter sees a matching enable comment:&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;// swiftlint:disable all&lt;/code&gt; &lt;code&gt;// swiftlint:enable all&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// swiftlint:disable all
let noWarning :String = &quot;&quot; // No warning about colons immediately after variable names.
let i = &quot;&quot; // Also no warning about short identifier names.
// swiftlint:enable all
let hasWarning :String = &quot;&quot; // Warning generated about colons immediately after variable names.
let y = &quot;&quot; // Warning generated about short identifier names.
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;It&#39;s also possible to modify a &lt;code&gt;disable&lt;/code&gt; or &lt;code&gt;enable&lt;/code&gt; command by appending &lt;code&gt;:previous&lt;/code&gt;, &lt;code&gt;:this&lt;/code&gt; or &lt;code&gt;:next&lt;/code&gt; for only applying the command to the previous, this (current) or next line respectively.&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// swiftlint:disable:next force_cast
let noWarning = NSNumber() as! Int
let hasWarning = NSNumber() as! Int
let noWarning2 = NSNumber() as! Int // swiftlint:disable:this force_cast
let noWarning3 = NSNumber() as! Int
// swiftlint:disable:previous force_cast
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Run &lt;code&gt;swiftlint rules&lt;/code&gt; to print a list of all available rules and their identifiers.&lt;/p&gt; 
&lt;h3&gt;Configuration&lt;/h3&gt; 
&lt;p&gt;Configure SwiftLint by adding a &lt;code&gt;.swiftlint.yml&lt;/code&gt; file from the directory you&#39;ll run SwiftLint from. The following parameters can be configured:&lt;/p&gt; 
&lt;p&gt;Rule inclusion:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;disabled_rules&lt;/code&gt;: Disable rules from the default enabled set.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;opt_in_rules&lt;/code&gt;: Enable rules that are not part of the default set. The special &lt;code&gt;all&lt;/code&gt; identifier will enable all opt in linter rules, except the ones listed in &lt;code&gt;disabled_rules&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;only_rules&lt;/code&gt;: Only the rules specified in this list will be enabled. Cannot be specified alongside &lt;code&gt;disabled_rules&lt;/code&gt; or &lt;code&gt;opt_in_rules&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;analyzer_rules&lt;/code&gt;: This is an entirely separate list of rules that are only run by the &lt;code&gt;analyze&lt;/code&gt; command. All analyzer rules are opt-in, so this is the only configurable rule list, there are no equivalents for &lt;code&gt;disabled_rules&lt;/code&gt; and &lt;code&gt;only_rules&lt;/code&gt;. The special &lt;code&gt;all&lt;/code&gt; identifier can also be used here to enable all analyzer rules, except the ones listed in &lt;code&gt;disabled_rules&lt;/code&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# By default, SwiftLint uses a set of sensible default rules you can adjust. Find all the available rules
# by running `swiftlint rules` or visiting https://realm.github.io/SwiftLint/rule-directory.html.

# Rules turned on by default can be disabled.
disabled_rules:
  - colon
  - comma
  - control_statement
  
# Rules turned off by default can be enabled.
opt_in_rules:
  - empty_count

# Alternatively, specify all rules explicitly by uncommenting this option and removing the above two.
# only_rules:
#   - empty_parameters
#   - vertical_whitespace

# Rules only run by `swiftlint analyze`. These are all opt-in.
analyzer_rules:
  - explicit_self

# Case-sensitive paths to include during linting. Directory paths supplied on the
# command line will be ignored. Wildcards are supported.
included: 
  - Sources

# Case-sensitive paths to ignore during linting. Takes precedence over `included`. Wildcards
# are supported.
excluded: 
  - Carthage
  - Pods
  - Sources/ExcludedFolder
  - Sources/ExcludedFile.swift
  - Sources/*/ExcludedFile.swift

# If true, SwiftLint will not fail if no lintable files are found.
allow_zero_lintable_files: false

# If true, SwiftLint will treat all warnings as errors.
strict: false

# If true, SwiftLint will treat all errors as warnings.
lenient: false

# The path to a baseline file, which will be used to filter out detected violations.
baseline: Baseline.json

# The path to save detected violations to as a new baseline.
write_baseline: Baseline.json

# If true, SwiftLint will check for updates after linting or analyzing.
check_for_updates: true

# Configurable rules can be customized. All rules support setting their severity level.
force_cast: warning # implicitly
force_try:
  severity: warning # explicitly
  
# Rules that have both warning and error levels can set just the warning level implicitly.
line_length: 110

# To set both levels implicitly, use an array.
type_body_length:
  - 300 # warning
  - 400 # error

# To set both levels explicitly, use a dictionary.
file_length:
  warning: 500
  error: 1200
  
# Naming rules can set warnings/errors for `min_length` and `max_length`. Additionally, they can
# set excluded names and allowed symbols.
type_name:
  min_length: 4 # warning
  max_length: # warning and error
    warning: 40
    error: 50
  excluded: i(Phone|Pad|Pod) # regex pattern
  allowed_symbols: [&quot;_&quot;]
identifier_name:
  min_length:
    error: 4 # only error
  excluded: # excluded via string array
    - id
    - URL
    - GlobalAPIKey
    
# The default reporter (SwiftLint&#39;s output format) can be configured as `checkstyle`, `codeclimate`, `csv`,
# `emoji`, `github-actions-logging`, `gitlab`, `html`, `json`, `junit`, `markdown`, `relative-path`, `sarif`,
# `sonarqube`, `summary`, or `xcode` (default).
reporter: &quot;xcode&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also use environment variables in your configuration file, by using &lt;code&gt;${SOME_VARIABLE}&lt;/code&gt; in a string.&lt;/p&gt; 
&lt;h3&gt;Defining Custom Rules&lt;/h3&gt; 
&lt;p&gt;In addition to the rules that the main SwiftLint project ships with, SwiftLint can also run two types of custom rules that you can define yourself in your own projects:&lt;/p&gt; 
&lt;h4&gt;1. Swift Custom Rules&lt;/h4&gt; 
&lt;p&gt;These rules are written the same way as the Swift-based rules that ship with SwiftLint so they&#39;re fast, accurate, can leverage SwiftSyntax, can be unit tested, and more.&lt;/p&gt; 
&lt;p&gt;Using these requires building SwiftLint with Bazel as described in &lt;a href=&quot;https://vimeo.com/820572803&quot;&gt;this video&lt;/a&gt; or its associated code in &lt;a href=&quot;https://github.com/jpsim/swiftlint-bazel-example&quot;&gt;github.com/jpsim/swiftlint-bazel-example&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;2. Regex Custom Rules&lt;/h4&gt; 
&lt;p&gt;You can define custom regex-based rules in your configuration file using the following syntax:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;custom_rules:
  # Rule identifier.
  pirates_beat_ninjas:
    # Optional regex that defines paths to include during linting.
    included:
      - &quot;.*\\.swift&quot;
    # Optional regex that defines paths to exclude during linting.
    excluded:
      - &quot;.*Test\\.swift&quot;
    # Optional rule name.
    name: &quot;Pirates Beat Ninjas&quot;
    # Matching pattern.
    regex: &quot;([nN]inja)&quot;
    # Number of regex capture group to highlight the rule violation at. Optional, defaults to 0 (the whole match).
    capture_group: 0
    # SyntaxKinds to match. optional.
    match_kinds:
      - comment
      - identifier
    # Optional violation message.
    message: &quot;Pirates are better than ninjas.&quot;
    # Optional violation severity.
    severity: error
  no_hiding_in_strings:
    regex: &quot;([nN]inja)&quot;
    # Syntax kinds to match. optional.
    match_kinds: string
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This is what the output would look like:&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/assets/custom-rule.png&quot; alt=&quot;Custom violations highlighted in the Xcode editor&quot; /&gt;&lt;/p&gt; 
&lt;p&gt;It is important to note that the regular expression pattern is used with the flags &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; enabled, that is &lt;code&gt;.&lt;/code&gt; &lt;a href=&quot;https://developer.apple.com/documentation/foundation/nsregularexpression/options/1412529-dotmatcheslineseparators&quot;&gt;matches newlines&lt;/a&gt; and &lt;code&gt;^&lt;/code&gt;/&lt;code&gt;$&lt;/code&gt; &lt;a href=&quot;https://developer.apple.com/documentation/foundation/nsregularexpression/options/1408263-anchorsmatchlines&quot;&gt;match the start and end of lines&lt;/a&gt;, respectively. If you do not want to have &lt;code&gt;.&lt;/code&gt; match newlines, for example, the regex can be prepended by &lt;code&gt;(?-s)&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;You can filter the matches by providing one or more &lt;code&gt;match_kinds&lt;/code&gt;, which will reject matches that include syntax kinds that are not present in this list. Here are all the possible syntax kinds:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;argument&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;attribute.builtin&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;attribute.id&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;buildconfig.id&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;buildconfig.keyword&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;comment&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;comment.mark&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;comment.url&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;doccomment&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;doccomment.field&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;identifier&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;keyword&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;number&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;objectliteral&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;parameter&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;placeholder&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;string&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;string_interpolation_anchor&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;typeidentifier&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;All syntax kinds used in a snippet of Swift code can be extracted asking &lt;a href=&quot;https://github.com/jpsim/SourceKitten&quot;&gt;SourceKitten&lt;/a&gt;. For example, &lt;code&gt;sourcekitten syntax --text &quot;struct S {}&quot;&lt;/code&gt; delivers&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;source.lang.swift.syntaxtype.keyword&lt;/code&gt; for the &lt;code&gt;struct&lt;/code&gt; keyword and&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;source.lang.swift.syntaxtype.identifier&lt;/code&gt; for its name &lt;code&gt;S&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;which match to &lt;code&gt;keyword&lt;/code&gt; and &lt;code&gt;identifier&lt;/code&gt; in the above list.&lt;/p&gt; 
&lt;p&gt;If using custom rules in combination with &lt;code&gt;only_rules&lt;/code&gt;, you must include the literal string &lt;code&gt;custom_rules&lt;/code&gt; in the &lt;code&gt;only_rules&lt;/code&gt; list:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;only_rules:
  - custom_rules

custom_rules:
  no_hiding_in_strings:
    regex: &quot;([nN]inja)&quot;
    match_kinds: string
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Unlike Swift custom rules, you can use official SwiftLint builds (e.g. from Homebrew) to run regex custom rules.&lt;/p&gt; 
&lt;h3&gt;Auto-correct&lt;/h3&gt; 
&lt;p&gt;SwiftLint can automatically correct certain violations. Files on disk are overwritten with a corrected version.&lt;/p&gt; 
&lt;p&gt;Please make sure to have backups of these files before running &lt;code&gt;swiftlint --fix&lt;/code&gt;, otherwise important data may be lost.&lt;/p&gt; 
&lt;p&gt;Standard linting is disabled while correcting because of the high likelihood of violations (or their offsets) being incorrect after modifying a file while applying corrections.&lt;/p&gt; 
&lt;h3&gt;Analyze&lt;/h3&gt; 
&lt;p&gt;The &lt;code&gt;swiftlint analyze&lt;/code&gt; command can lint Swift files using the full type-checked AST. The compiler log path containing the clean &lt;code&gt;swiftc&lt;/code&gt; build command invocation (incremental builds will fail) must be passed to &lt;code&gt;analyze&lt;/code&gt; via the &lt;code&gt;--compiler-log-path&lt;/code&gt; flag. e.g. &lt;code&gt;--compiler-log-path /path/to/xcodebuild.log&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;This can be obtained by&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;Cleaning DerivedData (incremental builds won&#39;t work with analyze)&lt;/li&gt; 
 &lt;li&gt;Running &lt;code&gt;xcodebuild -workspace {WORKSPACE}.xcworkspace -scheme {SCHEME} &amp;gt; xcodebuild.log&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Running &lt;code&gt;swiftlint analyze --compiler-log-path xcodebuild.log&lt;/code&gt;&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Analyzer rules tend to be considerably slower than lint rules.&lt;/p&gt; 
&lt;h2&gt;Using Multiple Configuration Files&lt;/h2&gt; 
&lt;p&gt;SwiftLint offers a variety of ways to include multiple configuration files. Multiple configuration files get merged into one single configuration that is then applied just as a single configuration file would get applied.&lt;/p&gt; 
&lt;p&gt;There are quite a lot of use cases where using multiple configuration files could be helpful:&lt;/p&gt; 
&lt;p&gt;For instance, one could use a team-wide shared SwiftLint configuration while allowing overrides in each project via a child configuration file.&lt;/p&gt; 
&lt;p&gt;Team-Wide Configuration:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;disabled_rules:
  - force_cast
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Project-Specific Configuration:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;opt_in_rules:
  - force_cast
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Child/Parent Configs (Locally)&lt;/h3&gt; 
&lt;p&gt;You can specify a &lt;code&gt;child_config&lt;/code&gt; and/or a &lt;code&gt;parent_config&lt;/code&gt; reference within a configuration file. These references should be local paths relative to the folder of the configuration file they are specified in. This even works recursively, as long as there are no cycles and no ambiguities.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;A child config is treated as a refinement and thus has a higher priority&lt;/strong&gt;, while a parent config is considered a base with lower priority in case of conflicts.&lt;/p&gt; 
&lt;p&gt;Here&#39;s an example, assuming you have the following file structure:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;ProjectRoot
    |_ .swiftlint.yml
    |_ .swiftlint_refinement.yml
    |_ Base
        |_ .swiftlint_base.yml
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;To include both the refinement and the base file, your &lt;code&gt;.swiftlint.yml&lt;/code&gt; should look like this:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;child_config: .swiftlint_refinement.yml
parent_config: Base/.swiftlint_base.yml
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When merging parent and child configs, &lt;code&gt;included&lt;/code&gt; and &lt;code&gt;excluded&lt;/code&gt; configurations are processed carefully to account for differences in the directory location of the containing configuration files.&lt;/p&gt; 
&lt;p&gt;Path merging follows these rules:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;&lt;code&gt;included&lt;/code&gt;/&lt;code&gt;excluded&lt;/code&gt; entries from each config are resolved relative to that config file&#39;s directory.&lt;/li&gt; 
 &lt;li&gt;Child entries override conflicting parent entries.&lt;/li&gt; 
 &lt;li&gt;The merged path lists are computed as:&lt;/li&gt; 
&lt;/ol&gt; 
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;merged.included = (parent.included - child.excluded) + child.included
merged.excluded = (parent.excluded - child.included) + child.excluded
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This means a child config can re-include a path excluded by its parent and can exclude a path included by its parent.&lt;/p&gt; 
&lt;h3&gt;Child/Parent Configs (Remote)&lt;/h3&gt; 
&lt;p&gt;Just as you can provide local &lt;code&gt;child_config&lt;/code&gt;/&lt;code&gt;parent_config&lt;/code&gt; references, instead of referencing local paths, you can just put urls that lead to configuration files. In order for SwiftLint to detect these remote references, they must start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;The referenced remote configuration files may even recursively reference other remote configuration files, but aren&#39;t allowed to include local references.&lt;/p&gt; 
&lt;p&gt;Using a remote reference, your &lt;code&gt;.swiftlint.yml&lt;/code&gt; could look like this:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;parent_config: https://myteamserver.com/our-base-swiftlint-config.yml
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Every time you run SwiftLint and have an Internet connection, SwiftLint tries to get a new version of every remote configuration that is referenced. If this request times out, a cached version is used if available. If there is no cached version available, SwiftLint fails – but no worries, a cached version should be there once SwiftLint has run successfully at least once.&lt;/p&gt; 
&lt;p&gt;If needed, the timeouts for the remote configuration fetching can be specified manually via the configuration file(s) using the &lt;code&gt;remote_timeout&lt;/code&gt;/&lt;code&gt;remote_timeout_if_cached&lt;/code&gt; specifiers. These values default to 2 seconds or 1 second, respectively.&lt;/p&gt; 
&lt;h3&gt;Command Line&lt;/h3&gt; 
&lt;p&gt;Instead of just providing one configuration file when running SwiftLint via the command line, you can also pass a hierarchy, where the first configuration is treated as a parent, while the last one is treated as the highest-priority child.&lt;/p&gt; 
&lt;p&gt;A simple example including just two configuration files looks like this:&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;swiftlint --config .swiftlint.yml --config .swiftlint_child.yml&lt;/code&gt;&lt;/p&gt; 
&lt;h3&gt;Nested Configurations&lt;/h3&gt; 
&lt;p&gt;In addition to a main configuration (the &lt;code&gt;.swiftlint.yml&lt;/code&gt; file in the root folder), you can put other configuration files named &lt;code&gt;.swiftlint.yml&lt;/code&gt; into the directory structure. For a given file, SwiftLint walks up from that file&#39;s directory towards the root configuration and uses the first nested &lt;code&gt;.swiftlint.yml&lt;/code&gt; it finds as a child config.&lt;/p&gt; 
&lt;p&gt;That nested config applies only to files in its directory subtree. Files in other subtrees continue using the main config (or their own nearest nested config).&lt;/p&gt; 
&lt;p&gt;Because SwiftLint stops at the first match while walking up the directory tree, &lt;strong&gt;at most one nested configuration is merged per file&lt;/strong&gt; (in addition to the main configuration).&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;.swiftlint.yml&lt;/code&gt; files are only considered as a nested configuration if they have not been used to build the main configuration already (e. g. by having been referenced via something like &lt;code&gt;child_config: Folder/.swiftlint.yml&lt;/code&gt;). Also, &lt;code&gt;parent_config&lt;/code&gt;/&lt;code&gt;child_config&lt;/code&gt; specifications of nested configurations are getting ignored because there&#39;s no sense to that.&lt;/p&gt; 
&lt;p&gt;If one (or more) SwiftLint file(s) are explicitly specified via the &lt;code&gt;--config&lt;/code&gt; parameter, that configuration will be treated as an override, no matter whether there exist other &lt;code&gt;.swiftlint.yml&lt;/code&gt; files somewhere within the directory. &lt;strong&gt;So if you want to use nested configurations, you can&#39;t use the &lt;code&gt;--config&lt;/code&gt; parameter.&lt;/strong&gt;&lt;/p&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint/raw/main/LICENSE&quot;&gt;MIT licensed.&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;About&lt;/h2&gt; 
&lt;p&gt;SwiftLint is utterly maintained by volunteers contributing to its success entirely in their free time. As such, SwiftLint isn&#39;t a commercial product in any way.&lt;/p&gt; 
&lt;p&gt;Be kind to the people maintaining SwiftLint as a hobby and accept that their time is limited. Support them by contributing to the project, reporting issues, and helping others in the community.&lt;/p&gt; 
&lt;p&gt;Special thanks go to &lt;a href=&quot;https://www.macstadium.com&quot;&gt;MacStadium&lt;/a&gt; for providing physical Mac mini machines to run our performance tests.&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/realm/SwiftLint/main/assets/macstadium.png&quot; alt=&quot;MacStadium&quot; /&gt;&lt;/p&gt; 
&lt;p&gt;We also thank Realm (now MongoDB) for their initial contributions and setup of the project.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/5aebe81cdbf782fe5b05890d82678dea992567850f69eadb7760860d22ce86fa/realm/SwiftLint" medium="image" />
      
    </item>
    
    <item>
      <title>h3nock/remux</title>
      <link>https://github.com/h3nock/remux</link>
      <description>&lt;p&gt;A native iOS client for remote tmux workspaces, designed to feel natural on iPhone.&lt;/p&gt;&lt;hr&gt;&lt;h1&gt;Remux&lt;/h1&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;A native iOS client for remote tmux workspaces.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://trendshift.io/repositories/91075?utm_source=repository-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-repository-91075&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; &lt;img src=&quot;https://trendshift.io/api/badge/repositories/91075&quot; alt=&quot;h3nock/remux | Trendshift&quot; width=&quot;250&quot; height=&quot;55&quot; /&gt; &lt;/a&gt; &lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/user-attachments/assets/e7482322-15f8-4f7d-aca4-83368fddd07c&quot;&gt;https://github.com/user-attachments/assets/e7482322-15f8-4f7d-aca4-83368fddd07c&lt;/a&gt;&lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://testflight.apple.com/join/fHqG1ruE&quot;&gt;Join the beta on TestFlight&lt;/a&gt; &lt;/p&gt; 
&lt;h2&gt;About&lt;/h2&gt; 
&lt;p&gt;Remux is a native iOS client for remote tmux workspaces, built on Ghostty. It brings tmux&#39;s session, window, and pane model into a mobile-first interface. It previews files and running dev servers straight from the terminal, and uploads photos and files, with markup for images.&lt;/p&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;tmux sessions&lt;/strong&gt;: Attach to running sessions or start new ones.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Windows and panes&lt;/strong&gt;: Swipe between windows, pick panes from a bottom sheet with live previews, and split, zoom, or close them.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Shortcut palette&lt;/strong&gt;: Run saved commands with a tap. Starter sets cover shell, Claude Code, and Codex, and you can add your own commands and groups.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Voice dictation&lt;/strong&gt;: Dictate text in the composer using on-device speech recognition.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: Upload photos and files to the server, with markup for images. The remote path is typed at the prompt.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;File preview&lt;/strong&gt;: Long-press a path in terminal output to preview it: code, images, PDFs, or HTML pages.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Localhost preview&lt;/strong&gt;: Long-press a localhost URL to open the dev server running on the remote machine, hot reload and WebSockets included.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Cursor control&lt;/strong&gt;: Hold the space bar or long-press in the terminal, then drag to place the cursor.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Direct SSH&lt;/strong&gt;: Remux connects straight to the server, with no relay and no account. Passwords and private keys are stored in the iOS Keychain, and trusted host keys are remembered.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Themes&lt;/strong&gt;: Ghostty default, Catppuccin Mocha, and Catppuccin Latte, with adjustable font size.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;p&gt;Remux is available as a public beta on TestFlight: &lt;a href=&quot;https://testflight.apple.com/join/fHqG1ruE&quot;&gt;testflight.apple.com/join/fHqG1ruE&lt;/a&gt;. You can also build from source.&lt;/p&gt; 
&lt;h2&gt;Building from Source&lt;/h2&gt; 
&lt;p&gt;Requirements:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Xcode with iOS 18 SDK support&lt;/li&gt; 
 &lt;li&gt;XcodeGen&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Fetch the prebuilt GhosttyKit framework:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;scripts/fetch_ghosttykit.sh
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Generate the Xcode project and build:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;xcodegen generate

xcodebuild build \
  -project Remux.xcodeproj \
  -scheme Remux \
  -destination &#39;generic/platform=iOS Simulator&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Run the tests:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;xcodebuild test \
  -project Remux.xcodeproj \
  -scheme Remux \
  -destination &#39;platform=iOS Simulator,name=iPhone 17,OS=latest&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;To build GhosttyKit yourself instead of fetching it, see &lt;a href=&quot;https://github.com/h3nock/remux-ghostty&quot;&gt;remux-ghostty&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/h3nock/remux/main/scripts/build_release_ghosttykit.sh&quot;&gt;scripts/build_release_ghosttykit.sh&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Acknowledgments&lt;/h2&gt; 
&lt;p&gt;Remux is built on &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt;&#39;s terminal core and uses &lt;a href=&quot;https://github.com/orlandos-nl/Citadel&quot;&gt;Citadel&lt;/a&gt; for SSH.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/6d3640df272df6f6cad991071bf4bf0ae39994cb77f5457cb8a8c67aed964b6a/h3nock/remux" medium="image" />
      
    </item>
    
    <item>
      <title>Alamofire/Alamofire</title>
      <link>https://github.com/Alamofire/Alamofire</link>
      <description>&lt;p&gt;Elegant HTTP Networking in Swift&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/Resources/AlamofireLogo.png&quot; alt=&quot;Alamofire: Elegant Networking in Swift&quot; /&gt;&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://img.shields.io/badge/Swift-6.0_6.1_6.2-Orange?style=flat-square&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Swift-6.0_6.1_6.2-orange?style=flat-square&quot; alt=&quot;Swift&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_vision_OS_Linux_Windows_Android-Green?style=flat-square&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_visionOS_Linux_Windows_Android-yellowgreen?style=flat-square&quot; alt=&quot;Platforms&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://img.shields.io/cocoapods/v/Alamofire.svg&quot;&gt;&lt;img src=&quot;https://img.shields.io/cocoapods/v/Alamofire.svg?style=flat-square&quot; alt=&quot;CocoaPods Compatible&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/Carthage/Carthage&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square&quot; alt=&quot;Carthage Compatible&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square&quot; alt=&quot;Swift Package Manager&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://forums.swift.org/c/related-projects/alamofire/37&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Swift_Forums-Alamofire-orange?style=flat-square&quot; alt=&quot;Swift Forums&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;Alamofire is an HTTP networking library written in Swift.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#component-libraries&quot;&gt;Component Libraries&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#migration-guides&quot;&gt;Migration Guides&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#communication&quot;&gt;Communication&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#installation&quot;&gt;Installation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#contributing&quot;&gt;Contributing&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#using-alamofire&quot;&gt;Usage&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#introduction&quot;&gt;&lt;strong&gt;Introduction -&lt;/strong&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#making-requests&quot;&gt;Making Requests&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#response-handling&quot;&gt;Response Handling&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#response-validation&quot;&gt;Response Validation&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#response-caching&quot;&gt;Response Caching&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;HTTP -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#http-methods&quot;&gt;HTTP Methods&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#%23request-parameters-and-parameter-encoders&quot;&gt;Parameters and Parameter Encoder&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#http-headers&quot;&gt;HTTP Headers&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#authentication&quot;&gt;Authentication&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Large Data -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#downloading-data-to-a-file&quot;&gt;Downloading Data to a File&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#uploading-data-to-a-server&quot;&gt;Uploading Data to a Server&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Tools -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#statistical-metrics&quot;&gt;Statistical Metrics&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Usage.md#curl-command-output&quot;&gt;cURL Command Output&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md&quot;&gt;Advanced Usage&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;strong&gt;URL Session -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#session&quot;&gt;Session Manager&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#sessiondelegate&quot;&gt;Session Delegate&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#request&quot;&gt;Request&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Routing -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#routing-requests&quot;&gt;Routing Requests&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#adapting-and-retrying-requests-with-requestinterceptor&quot;&gt;Adapting and Retrying Requests&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Model Objects -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#customizing-response-handlers&quot;&gt;Custom Response Handlers&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Advanced Concurrency -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#using-alamofire-with-swift-concurrency&quot;&gt;Swift Concurrency&lt;/a&gt; and &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#using-alamofire-with-combine&quot;&gt;Combine&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;Connection -&lt;/strong&gt; &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#security&quot;&gt;Security&lt;/a&gt;, &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/AdvancedUsage.md#network-reachability&quot;&gt;Network Reachability&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#open-radars&quot;&gt;Open Radars&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#donations&quot;&gt;Donations&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#license&quot;&gt;License&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;ul class=&quot;task-list&quot;&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_0&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_0&quot;&gt; Chainable Request / Response Methods&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_1&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_1&quot;&gt; Swift Concurrency Support Back to iOS 13, macOS 10.15, tvOS 13, and watchOS 6.&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_2&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_2&quot;&gt; Combine Support&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_3&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_3&quot;&gt; URL / JSON Parameter Encoding&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_4&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_4&quot;&gt; Upload File / Data / Stream / MultipartFormData&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_5&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_5&quot;&gt; Download File using Request or Resume Data&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_6&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_6&quot;&gt; Authentication with &lt;code&gt;URLCredential&lt;/code&gt;&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_7&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_7&quot;&gt; HTTP Response Validation&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_8&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_8&quot;&gt; Upload and Download Progress Closures with Progress&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_9&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_9&quot;&gt; cURL Command Output&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_10&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_10&quot;&gt; Dynamically Adapt and Retry Requests&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_11&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_11&quot;&gt; TLS Certificate and Public Key Pinning&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_12&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_12&quot;&gt; Network Reachability&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_13&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_13&quot;&gt; Comprehensive Unit and Integration Test Coverage&lt;/label&gt;&lt;/li&gt; 
 &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;cbx_14&quot; checked=&quot;true&quot; disabled=&quot;true&quot; /&gt;&lt;label for=&quot;cbx_14&quot;&gt; &lt;a href=&quot;https://alamofire.github.io/Alamofire&quot;&gt;Complete Documentation&lt;/a&gt;&lt;/label&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Write Requests Fast!&lt;/h2&gt; 
&lt;p&gt;Alamofire&#39;s compact syntax and extensive feature set allow requests with powerful features like automatic retry to be written in just a few lines of code.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Automatic String to URL conversion, Swift concurrency support, and automatic retry.
let response = await AF.request(&quot;https://httpbin.org/get&quot;, interceptor: .retryPolicy)
                       // Automatic HTTP Basic Auth.
                       .authenticate(username: &quot;user&quot;, password: &quot;pass&quot;)
                       // Caching customization.
                       .cacheResponse(using: .cache)
                       // Redirect customization.
                       .redirect(using: .follow)
                       // Validate response code and Content-Type.
                       .validate()
                       // Produce a cURL command for the request.
                       .cURLDescription { description in
                         print(description)
                       }
                       // Automatic Decodable support with background parsing.
                       .serializingDecodable(DecodableType.self)
                       // Await the full response with metrics and a parsed body.
                       .response
// Detailed response description for easy debugging.
debugPrint(response)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Component Libraries&lt;/h2&gt; 
&lt;p&gt;In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the &lt;a href=&quot;https://github.com/Alamofire/Foundation&quot;&gt;Alamofire Software Foundation&lt;/a&gt; to bring additional functionality to the Alamofire ecosystem.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/AlamofireImage&quot;&gt;AlamofireImage&lt;/a&gt; - An image library including image response serializers, &lt;code&gt;UIImage&lt;/code&gt; and &lt;code&gt;UIImageView&lt;/code&gt; extensions, custom image filters, an auto-purging in-memory cache, and a priority-based image downloading system.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/AlamofireNetworkActivityIndicator&quot;&gt;AlamofireNetworkActivityIndicator&lt;/a&gt; - Controls the visibility of the network activity indicator on iOS using Alamofire. It contains configurable delay timers to help mitigate flicker and can support &lt;code&gt;URLSession&lt;/code&gt; instances not managed by Alamofire.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Requirements&lt;/h2&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;Platform&lt;/th&gt; 
   &lt;th&gt;Minimum Swift Version&lt;/th&gt; 
   &lt;th&gt;Installation&lt;/th&gt; 
   &lt;th&gt;Status&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+&lt;/td&gt; 
   &lt;td&gt;6.0 / Xcode 16.0&lt;/td&gt; 
   &lt;td&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#cocoapods&quot;&gt;CocoaPods&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#carthage&quot;&gt;Carthage&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#manually&quot;&gt;Manual&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Fully Tested&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Linux&lt;/td&gt; 
   &lt;td&gt;Latest Only&lt;/td&gt; 
   &lt;td&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Building But Unsupported&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Windows&lt;/td&gt; 
   &lt;td&gt;Latest Only&lt;/td&gt; 
   &lt;td&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Building But Unsupported&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Android&lt;/td&gt; 
   &lt;td&gt;Latest Only&lt;/td&gt; 
   &lt;td&gt;&lt;a href=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/#swift-package-manager&quot;&gt;Swift Package Manager&lt;/a&gt;&lt;/td&gt; 
   &lt;td&gt;Building But Unsupported&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h4&gt;Known Issues on Linux and Windows&lt;/h4&gt; 
&lt;p&gt;Alamofire builds on Linux, Windows, and Android but there are missing features and many issues in the underlying &lt;code&gt;swift-corelibs-foundation&lt;/code&gt; that prevent full functionality and may cause crashes. These include:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;ServerTrustManager&lt;/code&gt; and associated certificate functionality is unavailable, so there is no certificate pinning and no client certificate support.&lt;/li&gt; 
 &lt;li&gt;Various methods of HTTP authentication may crash, including HTTP Basic and HTTP Digest. Crashes may occur if responses contain server challenges.&lt;/li&gt; 
 &lt;li&gt;Cache control through &lt;code&gt;CachedResponseHandler&lt;/code&gt; and associated APIs is unavailable, as the underlying delegate methods aren&#39;t called.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;URLSessionTaskMetrics&lt;/code&gt; are never gathered.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;WebSocketRequest&lt;/code&gt; is not available.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Due to these issues, Alamofire is unsupported on Linux, Windows, and Android. Please report any crashes to the &lt;a href=&quot;https://bugs.swift.org&quot;&gt;Swift bug reporter&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Migration Guides&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Alamofire%205.0%20Migration%20Guide.md&quot;&gt;Alamofire 5.0 Migration Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Alamofire%204.0%20Migration%20Guide.md&quot;&gt;Alamofire 4.0 Migration Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Alamofire%203.0%20Migration%20Guide.md&quot;&gt;Alamofire 3.0 Migration Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/Documentation/Alamofire%202.0%20Migration%20Guide.md&quot;&gt;Alamofire 2.0 Migration Guide&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Communication&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;If you &lt;strong&gt;need help with making network requests&lt;/strong&gt; using Alamofire, use &lt;a href=&quot;https://stackoverflow.com/questions/tagged/alamofire&quot;&gt;Stack Overflow&lt;/a&gt; and tag &lt;code&gt;alamofire&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;If you need to &lt;strong&gt;find or understand an API&lt;/strong&gt;, check &lt;a href=&quot;http://alamofire.github.io/Alamofire/&quot;&gt;our documentation&lt;/a&gt; or &lt;a href=&quot;https://developer.apple.com/documentation/foundation/url_loading_system&quot;&gt;Apple&#39;s documentation for &lt;code&gt;URLSession&lt;/code&gt;&lt;/a&gt;, on top of which Alamofire is built.&lt;/li&gt; 
 &lt;li&gt;If you need &lt;strong&gt;help with an Alamofire feature&lt;/strong&gt;, use &lt;a href=&quot;https://forums.swift.org/c/related-projects/alamofire&quot;&gt;our forum on swift.org&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;If you&#39;d like to &lt;strong&gt;discuss Alamofire best practices&lt;/strong&gt;, use &lt;a href=&quot;https://forums.swift.org/c/related-projects/alamofire&quot;&gt;our forum on swift.org&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;If you&#39;d like to &lt;strong&gt;discuss a feature request&lt;/strong&gt;, use &lt;a href=&quot;https://forums.swift.org/c/related-projects/alamofire&quot;&gt;our forum on swift.org&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;If you &lt;strong&gt;found a bug&lt;/strong&gt;, open an issue here on GitHub and follow the guide. The more detail the better!&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;h3&gt;Swift Package Manager&lt;/h3&gt; 
&lt;p&gt;The &lt;a href=&quot;https://swift.org/package-manager/&quot;&gt;Swift Package Manager&lt;/a&gt; is a tool for automating the distribution of Swift code and is integrated into the &lt;code&gt;swift&lt;/code&gt; compiler.&lt;/p&gt; 
&lt;p&gt;Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the &lt;code&gt;dependencies&lt;/code&gt; value of your &lt;code&gt;Package.swift&lt;/code&gt; or the Package list in Xcode.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;dependencies: [
    .package(url: &quot;https://github.com/Alamofire/Alamofire.git&quot;, .upToNextMajor(from: &quot;5.11.0&quot;))
]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Normally you&#39;ll want to depend on the &lt;code&gt;Alamofire&lt;/code&gt; target:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.product(name: &quot;Alamofire&quot;, package: &quot;Alamofire&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;But if you want to force Alamofire to be dynamically linked (do not do this unless you&#39;re sure you need it), you can depend on the &lt;code&gt;AlamofireDynamic&lt;/code&gt; target:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.product(name: &quot;AlamofireDynamic&quot;, package: &quot;Alamofire&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;CocoaPods&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://cocoapods.org&quot;&gt;CocoaPods&lt;/a&gt; is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your &lt;code&gt;Podfile&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;pod &#39;Alamofire&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Carthage&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/Carthage/Carthage&quot;&gt;Carthage&lt;/a&gt; is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your &lt;code&gt;Cartfile&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ogdl&quot;&gt;github &quot;Alamofire/Alamofire&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Manually&lt;/h3&gt; 
&lt;p&gt;If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually.&lt;/p&gt; 
&lt;h4&gt;Embedded Framework&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;Open up Terminal, &lt;code&gt;cd&lt;/code&gt; into your top-level project directory, and run the following command &quot;if&quot; your project is not initialized as a git repository:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git init
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Add Alamofire as a git &lt;a href=&quot;https://git-scm.com/docs/git-submodule&quot;&gt;submodule&lt;/a&gt; by running the following command:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git submodule add https://github.com/Alamofire/Alamofire.git
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Open the new &lt;code&gt;Alamofire&lt;/code&gt; folder, and drag the &lt;code&gt;Alamofire.xcodeproj&lt;/code&gt; into the Project Navigator of your application&#39;s Xcode project.&lt;/p&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;It should appear nested underneath your application&#39;s blue project icon. Whether it is above or below all the other Xcode groups does not matter.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Select the &lt;code&gt;Alamofire.xcodeproj&lt;/code&gt; in the Project Navigator and verify the deployment target matches that of your application target.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the &quot;Targets&quot; heading in the sidebar.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;In the tab bar at the top of that window, open the &quot;General&quot; panel.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Click on the &lt;code&gt;+&lt;/code&gt; button under the &quot;Embedded Binaries&quot; section.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;You will see two different &lt;code&gt;Alamofire.xcodeproj&lt;/code&gt; folders each with two different versions of the &lt;code&gt;Alamofire.framework&lt;/code&gt; nested inside a &lt;code&gt;Products&lt;/code&gt; folder.&lt;/p&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;It does not matter which &lt;code&gt;Products&lt;/code&gt; folder you choose from, but it does matter whether you choose the top or bottom &lt;code&gt;Alamofire.framework&lt;/code&gt;.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Select the top &lt;code&gt;Alamofire.framework&lt;/code&gt; for iOS and the bottom one for macOS.&lt;/p&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;You can verify which one you selected by inspecting the build log for your project. The build target for &lt;code&gt;Alamofire&lt;/code&gt; will be listed as &lt;code&gt;Alamofire iOS&lt;/code&gt;, &lt;code&gt;Alamofire macOS&lt;/code&gt;, &lt;code&gt;Alamofire tvOS&lt;/code&gt;, or &lt;code&gt;Alamofire watchOS&lt;/code&gt;.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;And that&#39;s it!&lt;/p&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;The &lt;code&gt;Alamofire.framework&lt;/code&gt; is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Contributing&lt;/h2&gt; 
&lt;p&gt;Before contributing to Alamofire, please read the instructions detailed in our &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/CONTRIBUTING.md&quot;&gt;contribution guide&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Open Radars&lt;/h2&gt; 
&lt;p&gt;The following radars have some effect on the current implementation of Alamofire.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;http://www.openradar.me/radar?id=5517037090635776&quot;&gt;&lt;code&gt;rdar://21349340&lt;/code&gt;&lt;/a&gt; - Compiler throwing warning due to toll-free bridging issue in the test case&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;rdar://26870455&lt;/code&gt; - Background URL Session Configurations do not work in the simulator&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;rdar://26849668&lt;/code&gt; - Some URLProtocol APIs do not properly handle &lt;code&gt;URLRequest&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Resolved Radars&lt;/h2&gt; 
&lt;p&gt;The following radars have been resolved over time after being filed against the Alamofire project.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;http://www.openradar.me/radar?id=5010235949318144&quot;&gt;&lt;code&gt;rdar://26761490&lt;/code&gt;&lt;/a&gt; - Swift string interpolation causing memory leak with common usage. 
  &lt;ul&gt; 
   &lt;li&gt;(Resolved): 9/1/17 in Xcode 9 beta 6.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;http://openradar.appspot.com/radar?id=4942308441063424&quot;&gt;&lt;code&gt;rdar://36082113&lt;/code&gt;&lt;/a&gt; - &lt;code&gt;URLSessionTaskMetrics&lt;/code&gt; failing to link on watchOS 3.0+ 
  &lt;ul&gt; 
   &lt;li&gt;(Resolved): Just add &lt;code&gt;CFNetwork&lt;/code&gt; to your linked frameworks.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;FB7624529&lt;/code&gt; - &lt;code&gt;urlSession(_:task:didFinishCollecting:)&lt;/code&gt; never called on watchOS 
  &lt;ul&gt; 
   &lt;li&gt;(Resolved): Metrics now collected on watchOS 7+.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;FAQ&lt;/h2&gt; 
&lt;h3&gt;What&#39;s the origin of the name Alamofire?&lt;/h3&gt; 
&lt;p&gt;Alamofire is named after the &lt;a href=&quot;https://aggie-horticulture.tamu.edu/wildseed/alamofire.html&quot;&gt;Alamo Fire flower&lt;/a&gt;, a hybrid variant of the Bluebonnet, the official state flower of Texas.&lt;/p&gt; 
&lt;h2&gt;Credits&lt;/h2&gt; 
&lt;p&gt;Alamofire is owned and maintained by the &lt;a href=&quot;http://alamofire.org&quot;&gt;Alamofire Software Foundation&lt;/a&gt;. You can follow them on Twitter at &lt;a href=&quot;https://twitter.com/AlamofireSF&quot;&gt;@AlamofireSF&lt;/a&gt; for project updates and releases.&lt;/p&gt; 
&lt;h3&gt;Security Disclosure&lt;/h3&gt; 
&lt;p&gt;If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to &lt;a href=&quot;mailto:security@alamofire.org&quot;&gt;security@alamofire.org&lt;/a&gt;. Please do not post it to a public issue tracker.&lt;/p&gt; 
&lt;h2&gt;Sponsorship&lt;/h2&gt; 
&lt;p&gt;The &lt;a href=&quot;https://github.com/Alamofire/Foundation#members&quot;&gt;ASF&lt;/a&gt; is looking to raise money to officially stay registered as a federal non-profit organization. Registering will allow Foundation members to gain some legal protections and also allow us to put donations to use, tax-free. Sponsoring the ASF will enable us to:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Pay our yearly legal fees to keep the non-profit in good status&lt;/li&gt; 
 &lt;li&gt;Pay for our mail servers to help us stay on top of all questions and security issues&lt;/li&gt; 
 &lt;li&gt;Potentially fund test servers to make it easier for us to test the edge cases&lt;/li&gt; 
 &lt;li&gt;Potentially fund developers to work on one of our projects full-time&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;The community adoption of the ASF libraries has been amazing. We are greatly humbled by your enthusiasm around the projects and want to continue to do everything we can to move the needle forward. With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members. If you use any of our libraries for work, see if your employers would be interested in donating. Any amount you can donate, whether once or monthly, to help us reach our goal would be greatly appreciated.&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/sponsors/Alamofire&quot;&gt;Sponsor Alamofire&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Supporters&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://macstadium.com&quot;&gt;MacStadium&lt;/a&gt; provides Alamofire with a free, hosted Mac mini.&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Alamofire/Alamofire/master/Resources/MacStadiumLogo.png&quot; alt=&quot;Powered by MacStadium&quot; /&gt;&lt;/p&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;Alamofire is released under the MIT license. &lt;a href=&quot;https://github.com/Alamofire/Alamofire/raw/master/LICENSE&quot;&gt;See LICENSE&lt;/a&gt; for details.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/1fae2fbe25a52f75b658683adfa4f1a366cd1c7df034daf09830d13b537e64df/Alamofire/Alamofire" medium="image" />
      
    </item>
    
    <item>
      <title>Ranchero-Software/NetNewsWire</title>
      <link>https://github.com/Ranchero-Software/NetNewsWire</link>
      <description>&lt;p&gt;RSS reader for macOS and iOS.&lt;/p&gt;&lt;hr&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/Technotes/Images/icon_1024.png&quot; height=&quot;128&quot; width=&quot;128&quot; style=&quot;display: block; margin: auto;&quot; /&gt; 
&lt;h1&gt;NetNewsWire&lt;/h1&gt; 
&lt;p&gt;NetNewsWire is a free and open-source feed reader for macOS and iOS.&lt;/p&gt; 
&lt;p&gt;It supports &lt;a href=&quot;https://cyber.harvard.edu/rss/rss.html&quot;&gt;RSS&lt;/a&gt;, &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc4287&quot;&gt;Atom&lt;/a&gt;, &lt;a href=&quot;https://jsonfeed.org/&quot;&gt;JSON Feed&lt;/a&gt;, and &lt;a href=&quot;https://github.com/scripting/Scripting-News/raw/master/rss-in-json/README.md&quot;&gt;RSS-in-JSON&lt;/a&gt; formats.&lt;/p&gt; 
&lt;p&gt;More info: &lt;a href=&quot;https://netnewswire.com/&quot;&gt;https://netnewswire.com/&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;You can &lt;a href=&quot;https://github.com/Ranchero-Software/NetNewsWire/issues&quot;&gt;report bugs and make feature requests&lt;/a&gt; here on GitHub. You can also &lt;a href=&quot;https://github.com/Ranchero-Software/NetNewsWire/releases/&quot;&gt;read change notes&lt;/a&gt; for current and previous releases.&lt;/p&gt; 
&lt;p&gt;Here’s &lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/Technotes/HowToSupportNetNewsWire.markdown&quot;&gt;How to Support NetNewsWire&lt;/a&gt;. Spoiler: don’t send money. 😃&lt;/p&gt; 
&lt;p&gt;(NetNewsWire’s Help menu has these links, so you don’t have to remember to come back to this page.)&lt;/p&gt; 
&lt;h4&gt;Community&lt;/h4&gt; 
&lt;p&gt;&lt;a href=&quot;https://discourse.netnewswire.com/&quot;&gt;Join the forum&lt;/a&gt; to talk with other NetNewsWire users —&amp;nbsp;and to help out, if you’d like to, by testing, coding, writing, providing feedback, or just helping us think things through. Everybody is welcome and encouraged to join.&lt;/p&gt; 
&lt;p&gt;Every community member is expected to abide by the &lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/CONTRIBUTING.md#code-of-conduct&quot;&gt;code of conduct&lt;/a&gt; which is included in the &lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/CONTRIBUTING.md&quot;&gt;Contributing&lt;/a&gt; page.&lt;/p&gt; 
&lt;h4&gt;Pull Requests&lt;/h4&gt; 
&lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/CONTRIBUTING.md&quot;&gt;Contributing&lt;/a&gt; page for our process. They key thing is to ask before doing a PR (before even starting work). The Contributing page goes into more detail as to why it’s important to ask first.&lt;/p&gt; 
&lt;h4&gt;Building&lt;/h4&gt; 
&lt;p&gt;You can build and test NetNewsWire without a paid developer account.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/Ranchero-Software/NetNewsWire.git
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can locally override the Xcode settings for code signing by creating a &lt;code&gt;DeveloperSettings.xcconfig&lt;/code&gt; file locally at the appropriate path. This allows for a pristine project with code signing set up with the appropriate developer ID and certificates, and for developer to be able to have local settings without needing to check in anything into source control.&lt;/p&gt; 
&lt;p&gt;You can do this in one of two ways: using the included &lt;code&gt;setup.sh&lt;/code&gt; script or by creating the folder structure and file manually.&lt;/p&gt; 
&lt;h5&gt;Using &lt;code&gt;setup.sh&lt;/code&gt;&lt;/h5&gt; 
&lt;ul&gt; 
 &lt;li&gt;Open Terminal and &lt;code&gt;cd&lt;/code&gt; into the NetNewsWire directory.&lt;/li&gt; 
 &lt;li&gt;Run this command to ensure you have execution rights for the script: &lt;code&gt;chmod +x setup.sh&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Execute the script with the following command: &lt;code&gt;./setup.sh&lt;/code&gt; and complete the answers.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h5&gt;Manually&lt;/h5&gt; 
&lt;p&gt;Make a directory &lt;code&gt;SharedXcodeSettings&lt;/code&gt; next to where you have this repository.&lt;/p&gt; 
&lt;p&gt;The directory structure is:&lt;/p&gt; 
&lt;pre&gt;&lt;code&gt;directory/
  SharedXcodeSettings/
    DeveloperSettings.xcconfig
  NetNewsWire/
    NetNewsWire.xcodeproj
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Example:&lt;/p&gt; 
&lt;p&gt;If your NetNewsWire Xcode project file is at: &lt;code&gt;/Users/name/projects/NetNewsWire/NetNewsWire.xcodeproj&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;Create your &lt;code&gt;DeveloperSettings.xcconfig&lt;/code&gt; file at &lt;code&gt;/Users/name/projects/SharedXcodeSettings/DeveloperSettings.xcconfig&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;Then create a plain text file in it: &lt;code&gt;SharedXcodeSettings/DeveloperSettings.xcconfig&lt;/code&gt; and give it the contents:&lt;/p&gt; 
&lt;pre&gt;&lt;code&gt;CODE_SIGN_IDENTITY = Mac Developer
DEVELOPMENT_TEAM = &amp;lt;Your Team ID&amp;gt;
CODE_SIGN_STYLE = Automatic
ORGANIZATION_IDENTIFIER = &amp;lt;Your Domain Name Reversed&amp;gt;
DEVELOPER_ENTITLEMENTS = -dev
PROVISIONING_PROFILE_SPECIFIER =
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Set &lt;code&gt;DEVELOPMENT_TEAM&lt;/code&gt; to your Apple supplied development team. You can use Keychain Access to &lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/Technotes/FindingYourDevelopmentTeamID.md&quot;&gt;find your development team ID&lt;/a&gt;. Set &lt;code&gt;ORGANIZATION_IDENTIFIER&lt;/code&gt; to a reversed domain name that you control or have made up. Note that &lt;code&gt;PROVISIONING_PROFILE_SPECIFIER&lt;/code&gt; should not have a value associated with it.&lt;/p&gt; 
&lt;p&gt;You can now open the &lt;code&gt;NetNewsWire.xcodeproj&lt;/code&gt; in Xcode.&lt;/p&gt; 
&lt;p&gt;Now you should be able to build without code signing errors and without modifying the NetNewsWire Xcode project. This is a special build of NetNewsWire with some functionality disabled. This is because we have API keys that can&#39;t be stored in the repository or shared between developers. Certain account types, like iCloud and Feedly, aren&#39;t enabled and the Reader View isn&#39;t enabled because of this.&lt;/p&gt; 
&lt;p&gt;If you have any problems, we will help you out in the forum (&lt;a href=&quot;https://raw.githubusercontent.com/Ranchero-Software/NetNewsWire/main/README.md#Community&quot;&gt;see above&lt;/a&gt;).&lt;/p&gt;</description>
      
      <media:content url="https://repository-images.githubusercontent.com/91977145/f3bb8a00-679a-11ea-8862-2c186702d38c" medium="image" />
      
    </item>
    
    <item>
      <title>LiveContainer/LiveContainer</title>
      <link>https://github.com/LiveContainer/LiveContainer</link>
      <description>&lt;p&gt;Run iOS apps without actually installing them!&lt;/p&gt;&lt;hr&gt;&lt;div align=&quot;center&quot;&gt; 
 &lt;img width=&quot;217&quot; height=&quot;217&quot; src=&quot;https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png&quot; alt=&quot;Logo&quot; /&gt; 
&lt;/div&gt; 
&lt;div align=&quot;center&quot;&gt; 
 &lt;h1&gt;&lt;b&gt;LiveContainer&lt;/b&gt;&lt;/h1&gt; 
 &lt;p&gt;&lt;i&gt;An app launcher that runs iOS apps without actually installing them! &lt;/i&gt;&lt;/p&gt; 
&lt;/div&gt; 
&lt;h6 align=&quot;center&quot;&gt; &lt;p&gt;Crowdin Project: &lt;a href=&quot;https://crowdin.com/project/livecontainer&quot;&gt;&lt;img src=&quot;https://badges.crowdin.net/livecontainer/localized.svg?sanitize=true&quot; alt=&quot;Crowdin&quot; /&gt;&lt;/a&gt; &amp;nbsp;| &amp;nbsp; Documentation:&lt;a href=&quot;https://livecontainer.github.io/docs/intro&quot;&gt;liveconainer.github.io&lt;/a&gt;&lt;/p&gt; &lt;/h6&gt;
&lt;h1&gt;LiveContainer&lt;/h1&gt; 
&lt;ul&gt; 
 &lt;li&gt;LiveContainer is an app launcher (not emulator or hypervisor) that allows you to run iOS apps inside it.&lt;/li&gt; 
 &lt;li&gt;Allows you to install unlimited apps (3 app/10 app id free developer account limit does not apply here) with only one app &amp;amp; app id. You can also have multiple versions of an app installed with multiple data containers.&lt;/li&gt; 
 &lt;li&gt;(Below iOS 26) When JIT is available, codesign is entirely bypassed, no need to sign your apps before installing. Otherwise, your app will be signed with the same certificate used by LiveContainer.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-caution&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-stop mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Caution&lt;/p&gt;
 &lt;p&gt;&lt;strong&gt;Important Notice Regarding Third-Party Builds of LiveContainer&lt;/strong&gt;&lt;/p&gt; 
 &lt;p&gt;We have recently noticed the appearance of certain closed-source third-party builds of LiveContainer. Please be aware that all your apps are installed within LiveContainer, which means these third-party builds &lt;strong&gt;have full access to your data, including sensitive information such as keychain items and login credentials&lt;/strong&gt;.&lt;/p&gt; 
 &lt;p&gt;Furthermore, please note that we do not provide any support for issues of these third-party builds.&lt;/p&gt; 
&lt;/div&gt; 
&lt;h1&gt;Installation&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;LiveContainer comes with a standalone version and a version with built-in SideStore. &lt;a href=&quot;https://livecontainer.github.io/docs/installation&quot;&gt;Please read the install guide here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;If you encounter any issue please &lt;a href=&quot;https://livecontainer.github.io/docs/faq&quot;&gt;read our FAQ here&lt;/a&gt;&lt;/p&gt; 
&lt;h3&gt;Standalone&lt;/h3&gt; 
&lt;table&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt; Stable &lt;/td&gt; 
   &lt;td&gt; &lt;a href=&quot;https://stikstore.app/altdirect/?url=https://github.com/LiveContainer/LiveContainer/releases/download/1.0/apps.json&amp;amp;exclude=livecontainer&quot; target=&quot;_blank&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/AltSource_Blue.png&quot; alt=&quot;Add AltSource&quot; width=&quot;200&quot; /&gt; &lt;/a&gt; &lt;/td&gt; 
   &lt;td&gt; &lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/releases/latest/download/LiveContainer.ipa&quot; target=&quot;_blank&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/Download_Blue.png&quot; alt=&quot;Download .ipa&quot; width=&quot;200&quot; /&gt; &lt;/a&gt; &lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt; Nightly &lt;/td&gt; 
   &lt;td&gt; &lt;a href=&quot;https://stikstore.app/altdirect/?url=https://github.com/LiveContainer/LiveContainer/releases/download/nightly/apps_nightly.json&amp;amp;exclude=livecontainer&quot; target=&quot;_blank&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/AltSource_Blue.png&quot; alt=&quot;Add AltSource&quot; width=&quot;200&quot; /&gt; &lt;/a&gt; &lt;/td&gt; 
   &lt;td&gt; &lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/releases/download/nightly/LiveContainer.ipa&quot; target=&quot;_blank&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/Download_Blue.png&quot; alt=&quot;Download .ipa&quot; width=&quot;200&quot; /&gt; &lt;/a&gt; &lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;h3&gt;LiveContainer+SideStore&lt;/h3&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;Stable&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;Nightly&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/releases/latest/download/LiveContainer+SideStore.ipa&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/Download_Blue.png&quot; alt=&quot;Download .ipa&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/releases/download/nightly/LiveContainer+SideStore.ipa&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/StikStore/altdirect/refs/heads/main/assets/png/Download_Blue.png&quot; alt=&quot;Download .ipa&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h2&gt;Requirements&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;iOS/iPadOS 15+ 
  &lt;ul&gt; 
   &lt;li&gt;Multitasking requires iOS/iPadOS 16.0+&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;AltStore 2.0+ / SideStore 0.6.0+&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h1&gt;Features &amp;amp; Guides&lt;/h1&gt; 
&lt;h3&gt;Installing Apps&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Open LiveContainer, tap the plus icon in the upper right hand corner and select IPA files to install.&lt;/li&gt; 
 &lt;li&gt;Choose the app you want to open in the next launch.&lt;/li&gt; 
 &lt;li&gt;You can long-press the app to manage it.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/add-to-home-screen&quot;&gt;Add Apps to Home Screen&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/multiple-livecontainers&quot;&gt;Multiple LiveContainers&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;Using multiple LiveContainers allows you to run multiples different apps simultaneously, with &lt;em&gt;almost&lt;/em&gt; seamless data transfer between the LiveContainers.&lt;/p&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/multitask&quot;&gt;Multitasking&lt;/a&gt;&lt;/h3&gt; 
&lt;p&gt;You can now launch multiple apps simultaneously in in-app virtual windows. These windows can be resized, scaled, and even displayed using the native Picture-in-Picture (PiP) feature. On iPads, apps can run in native window mode, displaying each app in a separate system window. And if you wish, you can choose to run apps in multitasking mode by default in settings.&lt;/p&gt; 
&lt;p&gt;To use multitasking, hold its banner and tap &lt;strong&gt;&quot;Multitask&quot;&lt;/strong&gt;. You can also make Multitask the default launch mode in settings.&lt;/p&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; 
 &lt;ol&gt; 
  &lt;li&gt;To use multitasking, ensure you select &lt;strong&gt;&quot;Keep App Extensions&quot;&lt;/strong&gt; when installing via SideStore/AltStore.&lt;/li&gt; 
  &lt;li&gt;If you want to enable JIT for multitasked apps, you’ll need a JIT enabler that supports attaching by PID. (StikDebug)&lt;/li&gt; 
 &lt;/ol&gt; 
&lt;/div&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/jit-support&quot;&gt;JIT Support&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/tweaks&quot;&gt;Installing external tweaks&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/containers-and-external-data&quot;&gt;Multiple Containers/External Containers&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;&lt;a href=&quot;https://livecontainer.github.io/docs/guides/lock-app&quot;&gt;Hiding Apps&lt;/a&gt;&lt;/h3&gt; 
&lt;h3&gt;Fix File Picker &amp;amp; Local Notification&lt;/h3&gt; 
&lt;p&gt;Some apps may experience issues with their file pickers or not be able to apply for notification permission in LiveContainer. To resolve this, enable &quot;Fix File Picker&quot; &amp;amp; &quot;Fix Local Notifications&quot; accordingly in the app-specific settings.&lt;/p&gt; 
&lt;h3&gt;&quot;Open In App&quot; Support&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;You can simply share a URL or a file to app simply by using iOS&#39;s native share sheet. In share sheet, select LiveContainer, and LiveContainer will ask you which app you&#39;d like to open that URL/file in.&lt;/li&gt; 
 &lt;li&gt;What&#39;s more, you also can tap the link icon in the top-right corner of the &quot;Apps&quot; tab and input the URL. LiveContainer will detect the appropriate app and ask if you want to launch it.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Compatibility&lt;/h2&gt; 
&lt;p&gt;Unfortunately, not all apps work in LiveContainer, so we have a &lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/labels/compatibility&quot;&gt;compatibility list&lt;/a&gt; to tell if there is apps that have issues. If they aren&#39;t on this list, then it&#39;s likely going run. However, if it doesn&#39;t work, please make an &lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/issues/new/choose&quot;&gt;issue&lt;/a&gt; about it.&lt;/p&gt; 
&lt;h2&gt;Building&lt;/h2&gt; 
&lt;p&gt;Open Xcode, edit &lt;code&gt;DEVELOPMENT_TEAM[config=Debug]&lt;/code&gt; in &lt;code&gt;xcconfigs/Global.xcconfig&lt;/code&gt; to your team id and compile.&lt;/p&gt; 
&lt;h2&gt;Project structure&lt;/h2&gt; 
&lt;h3&gt;Main executable&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Core of LiveContainer&lt;/li&gt; 
 &lt;li&gt;Contains the logic of setting up guest environment and loading guest app.&lt;/li&gt; 
 &lt;li&gt;If no app is selected, it loads LiveContainerSwiftUI.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;LiveContainerSwiftUI&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;SwiftUI rewrite of LiveContainerUI (by @hugeBlack)&lt;/li&gt; 
 &lt;li&gt;Language file &lt;code&gt;Localizable.xcstrings&lt;/code&gt; is in here for multilingual support. To help us translate LiveContainer, please visit &lt;a href=&quot;https://crowdin.com/project/livecontainer&quot;&gt;our crowdin project&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;MultitaskSupport&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Contains the implementation of multitasking feature.&lt;/li&gt; 
 &lt;li&gt;Based on &lt;a href=&quot;https://github.com/khanhduytran0/FrontBoardAppLauncher&quot;&gt;FrontBoardAppLauncher&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;SideStore&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Supporting code for SideStore&#39;s app refreshing integration&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;TweakLoader&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;A simple tweak injector, which loads CydiaSubstrate and loads tweaks.&lt;/li&gt; 
 &lt;li&gt;Injected to every app you install in LiveContainer.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;ZSign&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;The app signer shipped with LiveContainer.&lt;/li&gt; 
 &lt;li&gt;Originally made by &lt;a href=&quot;https://github.com/zhlynn/zsign&quot;&gt;zhlynn&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;LiveContainer uses &lt;a href=&quot;https://github.com/khcrysalis/Feather&quot;&gt;Feather&#39;s&lt;/a&gt; version of ZSign modified by khcrysalis.&lt;/li&gt; 
 &lt;li&gt;Changes are made to meet LiveContainer&#39;s needs.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;How does it work?&lt;/h2&gt; 
&lt;h3&gt;Patching guest executable&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Patch &lt;code&gt;__PAGEZERO&lt;/code&gt; segment: 
  &lt;ul&gt; 
   &lt;li&gt;Change &lt;code&gt;vmaddr&lt;/code&gt; to &lt;code&gt;0xFFFFC000&lt;/code&gt; (&lt;code&gt;0x100000000 - 0x4000&lt;/code&gt;)&lt;/li&gt; 
   &lt;li&gt;Change &lt;code&gt;vmsize&lt;/code&gt; to &lt;code&gt;0x4000&lt;/code&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;Change &lt;code&gt;MH_EXECUTE&lt;/code&gt; to &lt;code&gt;MH_DYLIB&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;Inject a load command to load &lt;code&gt;TweakLoader.dylib&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Patching &lt;code&gt;@executable_path&lt;/code&gt;&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Hook &lt;code&gt;dyld4::APIs::_NSGetExecutablePath&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Call &lt;code&gt;_NSGetExecutablePath&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Replace &lt;code&gt;config.process.mainExecutablePath&lt;/code&gt; 
  &lt;ul&gt; 
   &lt;li&gt;Calculate address of &lt;code&gt;config.process.mainExecutablePath&lt;/code&gt; using &lt;code&gt;dyld4::APIs&lt;/code&gt; instance (passed as first parameter)&lt;/li&gt; 
   &lt;li&gt;Use &lt;code&gt;builtin_vm_protect&lt;/code&gt; or TPRO unlock to make it writable&lt;/li&gt; 
   &lt;li&gt;Replace the address with one we have control of&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;Put the original &lt;code&gt;dyld4::APIs::_NSGetExecutablePath&lt;/code&gt; back&lt;/li&gt; 
&lt;/ul&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;Old Method&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;Call &lt;code&gt;_NSGetExecutablePath&lt;/code&gt; with an invalid buffer pointer input -&amp;gt; SIGSEGV&lt;/li&gt; 
  &lt;li&gt;Do some &lt;a href=&quot;https://github.com/khanhduytran0/LiveContainer/raw/5ef1e6a/main.m#L74-L115&quot;&gt;magic stuff&lt;/a&gt; to overwrite the contents of executable_path.&lt;/li&gt; 
 &lt;/ul&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;Patching &lt;code&gt;NSBundle.mainBundle&lt;/code&gt;&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;This property is overwritten with the guest app&#39;s bundle.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Bypassing Library Validation&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;JIT is optional to bypass codesigning. In JIT-less mode, all executables are signed so this does not apply.&lt;/li&gt; 
 &lt;li&gt;Derived from &lt;a href=&quot;https://blog.xpnsec.com/restoring-dyld-memory-loading&quot;&gt;Restoring Dyld Memory Loading&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;dlopening the executable&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Call &lt;code&gt;dlopen&lt;/code&gt; with the guest app&#39;s executable&lt;/li&gt; 
 &lt;li&gt;TweakLoader loads all tweaks in the selected folder&lt;/li&gt; 
 &lt;li&gt;Find the entry point&lt;/li&gt; 
 &lt;li&gt;Jump to the entry point&lt;/li&gt; 
 &lt;li&gt;The guest app&#39;s entry point calls &lt;code&gt;UIApplicationMain&lt;/code&gt; and start up like any other iOS apps.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Multi-Account support &amp;amp; Keychain Semi-Separation&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/entitlements.xml&quot;&gt;128 keychain access groups&lt;/a&gt; are created and LiveContainer allocates them randomly to each container of the same app. So you can create 128 container with different keychain access groups.&lt;/p&gt; 
&lt;h2&gt;Limitations&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Entitlements from the guest app are not applied to the host app. This isn&#39;t a big deal since sideloaded apps requires only basic entitlements.&lt;/li&gt; 
 &lt;li&gt;App Permissions are globally applied.&lt;/li&gt; 
 &lt;li&gt;Guest app containers are not sandboxed. This means one guest app can access other guest apps&#39; data.&lt;/li&gt; 
 &lt;li&gt;App extensions aren&#39;t supported. they cannot be registered because: LiveContainer is sandboxed, SpringBoard doesn&#39;t know what apps are installed in LiveContainer, and they take up App ID.&lt;/li&gt; 
 &lt;li&gt;Multitasking can be achieved by using multiple LiveContainer and the multitasking feature. However, while we were able to fix physical keyboard input issue on iPadOS (&lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/issues/524&quot;&gt;https://github.com/LiveContainer/LiveContainer/issues/524&lt;/a&gt;), iPhone Mirroring uses different checks which still broke it (&lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/issues/793&quot;&gt;https://github.com/LiveContainer/LiveContainer/issues/793&lt;/a&gt;).&lt;/li&gt; 
 &lt;li&gt;Remote push notification will not work&lt;/li&gt; 
 &lt;li&gt;Querying custom URL schemes might not work(?)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;TODO&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Use ChOma instead of custom MachO parser&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/LiveContainer/LiveContainer/raw/main/LICENSE&quot;&gt;GNU Affero General Public License v3.0&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;Credits&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://blog.xpnsec.com/restoring-dyld-memory-loading&quot;&gt;xpn&#39;s blogpost: Restoring Dyld Memory Loading&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/pinauten/PatchfinderUtils/raw/master/Sources/CFastFind/CFastFind.c&quot;&gt;LinusHenze&#39;s CFastFind&lt;/a&gt;: &lt;a href=&quot;https://github.com/pinauten/PatchfinderUtils/raw/master/LICENSE&quot;&gt;MIT license&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/opa334/litehook&quot;&gt;litehook&lt;/a&gt;: &lt;a href=&quot;https://github.com/opa334/litehook/raw/main/LICENSE&quot;&gt;MIT license&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;@haxi0 &amp;amp; @m1337v for icon&lt;/li&gt; 
 &lt;li&gt;@Vishram1123 for the initial shortcut implementation.&lt;/li&gt; 
 &lt;li&gt;@hugeBlack for SwiftUI contribution&lt;/li&gt; 
 &lt;li&gt;@Staubgeborener for automatic AltStore/SideStore source updater&lt;/li&gt; 
 &lt;li&gt;@fkunn1326 for improved app hiding&lt;/li&gt; 
 &lt;li&gt;@slds1 for dynamic color feature&lt;/li&gt; 
 &lt;li&gt;@Vishram1123 for iOS 26+ JIT Script Support&lt;/li&gt; 
 &lt;li&gt;@StephenDev0 for AltStore source support&lt;/li&gt; 
&lt;/ul&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/088556d3811d2f63f2976183f1f41459d50bcc1553656df1574caa8d2d109d44/LiveContainer/LiveContainer" medium="image" />
      
    </item>
    
    <item>
      <title>linearmouse/linearmouse</title>
      <link>https://github.com/linearmouse/linearmouse</link>
      <description>&lt;p&gt;The mouse and trackpad utility for Mac.&lt;/p&gt;&lt;hr&gt;&lt;h1 align=&quot;center&quot;&gt; &lt;a href=&quot;https://linearmouse.app&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/linearmouse/linearmouse/main/logo.svg?sanitize=true&quot; width=&quot;128&quot; height=&quot;128&quot; /&gt; &lt;br /&gt; LinearMouse &lt;/a&gt; &lt;/h1&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://github.com/linearmouse/linearmouse/releases/latest&quot;&gt;&lt;img alt=&quot;GitHub release (latest SemVer)&quot; src=&quot;https://img.shields.io/github/v/release/linearmouse/linearmouse?sort=semver&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/linearmouse/linearmouse/releases/latest/download/LinearMouse.dmg&quot;&gt;&lt;img src=&quot;https://img.shields.io/github/downloads/linearmouse/linearmouse/total&quot; alt=&quot;Downloads&quot; /&gt;&lt;/a&gt; &lt;img src=&quot;https://img.shields.io/github/license/linearmouse/linearmouse&quot; alt=&quot;MIT License&quot; /&gt; &lt;a href=&quot;https://crowdin.com/project/linearmouse&quot;&gt;&lt;img src=&quot;https://badges.crowdin.net/linearmouse/localized.svg?sanitize=true&quot; alt=&quot;Crowdin&quot; /&gt;&lt;/a&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; The mouse and trackpad utility for Mac. &lt;/p&gt; 
&lt;h2&gt;Get started&lt;/h2&gt; 
&lt;p&gt;Please visit &lt;a href=&quot;https://linearmouse.app&quot;&gt;https://linearmouse.app&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Contribute&lt;/h2&gt; 
&lt;p&gt;Please read the &lt;a href=&quot;https://raw.githubusercontent.com/linearmouse/linearmouse/main/CONTRIBUTING.md&quot;&gt;contributing guide&lt;/a&gt; before making a pull request.&lt;/p&gt; 
&lt;h2&gt;Help translate&lt;/h2&gt; 
&lt;p&gt;Please sign up for Crowdin and join our &lt;a href=&quot;https://crowdin.com/project/linearmouse&quot;&gt;Crowdin project&lt;/a&gt; to translate LinearMouse into supported languages. It is recommended to sign in Crowdin using GitHub, so that I can add you as a co-author when I merge the pull request.&lt;/p&gt; 
&lt;p&gt;If you want to add a new language, please &lt;a href=&quot;https://github.com/linearmouse/linearmouse/issues/new&quot;&gt;create a new issue&lt;/a&gt; and I will be happy to enable that language for you to translate.&lt;/p&gt; 
&lt;p&gt;I&#39;m not a native English speaker, so if you find any English localization issues, feel free to correct me by &lt;a href=&quot;https://github.com/linearmouse/linearmouse/edit/main/LinearMouse/en.lproj/Localizable.strings&quot;&gt;creating a pull request&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Sponsors&lt;/h2&gt; 
&lt;p&gt;Please visit &lt;a href=&quot;https://go.linearmouse.app/donate&quot;&gt;https://go.linearmouse.app/donate&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Credits&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/noah-nuebling/mac-mouse-fix&quot;&gt;Mac Mouse Fix&lt;/a&gt; - The way to modify the pointer speed (sensitivity) is inspired by Mac Mouse Fix.&lt;/li&gt; 
&lt;/ul&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/14852cd077e3da50184c9237a6b60223f97c786d8bfb20feffa9659681c48555/linearmouse/linearmouse" medium="image" />
      
    </item>
    
    <item>
      <title>swiftlang/swift</title>
      <link>https://github.com/swiftlang/swift</link>
      <description>&lt;p&gt;The Swift Programming Language&lt;/p&gt;&lt;hr&gt;&lt;picture&gt; 
 &lt;source media=&quot;(prefers-color-scheme: dark)&quot; srcset=&quot;https://www.swift.org/assets/images/swift~dark.svg&quot; /&gt; 
 &lt;img src=&quot;https://www.swift.org/assets/images/swift.svg?sanitize=true&quot; alt=&quot;Swift logo&quot; height=&quot;70&quot; /&gt; 
&lt;/picture&gt; 
&lt;h1&gt;Swift Programming Language&lt;/h1&gt; 
&lt;h2&gt;Welcome to Swift&lt;/h2&gt; 
&lt;p&gt;Swift is a high-performance system programming language. It has a clean and modern syntax, offers seamless access to existing C and Objective-C code and frameworks, and is memory-safe by default.&lt;/p&gt; 
&lt;p&gt;Although inspired by Objective-C and many other languages, Swift is not itself a C-derived language. As a complete and independent language, Swift packages core features like flow control, data structures, and functions, with high-level constructs like objects, protocols, closures, and generics. Swift embraces modules, eliminating the need for headers and the code duplication they entail.&lt;/p&gt; 
&lt;p&gt;To learn more about using the language, visit &lt;a href=&quot;https://swift.org/documentation/&quot;&gt;swift.org&lt;/a&gt;. To learn more about the compiler&#39;s internal design, see the &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/README.md&quot;&gt;documentation index&lt;/a&gt;.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#contributing-to-swift&quot;&gt;Contributing to Swift&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#getting-started&quot;&gt;Getting Started&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#swift-toolchains&quot;&gt;Swift Toolchains&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#build-failures&quot;&gt;Build Failures&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#learning-more&quot;&gt;Learning More&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Contributing to Swift&lt;/h2&gt; 
&lt;p&gt;Contributions to Swift are welcomed and encouraged! Please see the &lt;a href=&quot;https://swift.org/contributing/&quot;&gt;Contributing to Swift guide&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Before submitting the pull request, please make sure you have &lt;a href=&quot;https://github.com/apple/swift/raw/main/docs/ContinuousIntegration.md&quot;&gt;tested your changes&lt;/a&gt; and that they follow the Swift project &lt;a href=&quot;https://swift.org/contributing/#contributing-code&quot;&gt;guidelines for contributing code&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;To be a truly great community, &lt;a href=&quot;https://swift.org/&quot;&gt;Swift.org&lt;/a&gt; needs to welcome developers from all walks of life, with different backgrounds, and with a wide range of experience. A diverse and friendly community will have more great ideas, more unique perspectives, and produce more great code. We will work diligently to make the Swift community welcoming to everyone.&lt;/p&gt; 
&lt;p&gt;To give clarity of what is expected of our members, Swift has adopted the code of conduct defined by the Contributor Covenant. This document is used across many open source communities, and we think it articulates our values well. For more, see the &lt;a href=&quot;https://swift.org/code-of-conduct/&quot;&gt;Code of Conduct&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Getting Started&lt;/h2&gt; 
&lt;p&gt;If you are interested in:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Contributing fixes and features to the compiler: See our &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/FirstPullRequest.md&quot;&gt;How to Submit Your First Pull Request guide&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Building the compiler as a one-off: See our &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/GettingStarted.md&quot;&gt;Getting Started guide&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Building a toolchain as a one-off: Follow the &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/GettingStarted.md&quot;&gt;Getting Started guide&lt;/a&gt; up until the &quot;Building the project&quot; section. After that, follow the instructions in the &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/#swift-toolchains&quot;&gt;Swift Toolchains&lt;/a&gt; section below.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;We also have an &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/FAQ.md&quot;&gt;FAQ&lt;/a&gt; that answers common questions.&lt;/p&gt; 
&lt;h3&gt;Swift Toolchains&lt;/h3&gt; 
&lt;h4&gt;Building&lt;/h4&gt; 
&lt;p&gt;Swift toolchains are created using the script &lt;a href=&quot;https://github.com/apple/swift/raw/main/utils/build-toolchain&quot;&gt;build-toolchain&lt;/a&gt;. This script is used by &lt;a href=&quot;http://swift.org&quot;&gt;swift.org&lt;/a&gt;&#39;s CI to produce snapshots and can allow for one to locally reproduce such builds for development or distribution purposes. A typical invocation looks like the following:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;  $ ./swift/utils/build-toolchain $BUNDLE_PREFIX
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;where &lt;code&gt;$BUNDLE_PREFIX&lt;/code&gt; is a string that will be prepended to the build date to give the bundle identifier of the toolchain&#39;s &lt;code&gt;Info.plist&lt;/code&gt;. For instance, if &lt;code&gt;$BUNDLE_PREFIX&lt;/code&gt; was &lt;code&gt;com.example&lt;/code&gt;, the toolchain produced will have the bundle identifier &lt;code&gt;com.example.YYYYMMDD&lt;/code&gt;. It will be created in the directory you run the script with a filename of the form: &lt;code&gt;swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;Beyond building the toolchain, &lt;code&gt;build-toolchain&lt;/code&gt; also supports the following (non-exhaustive) set of useful options:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;--dry-run&lt;/code&gt;: Perform a dry run build. This is off by default.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;--test&lt;/code&gt;: Test the toolchain after it has been compiled. This is off by default.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;--distcc&lt;/code&gt;: Use distcc to speed up the build by distributing the C++ part of the swift build. This is off by default.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;--sccache&lt;/code&gt;: Use sccache to speed up subsequent builds of the compiler by caching more C++ build artifacts. This is off by default.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;More options may be added over time. Please pass &lt;code&gt;--help&lt;/code&gt; to &lt;code&gt;build-toolchain&lt;/code&gt; to see the full set of options.&lt;/p&gt; 
&lt;h4&gt;Installing into Xcode&lt;/h4&gt; 
&lt;p&gt;On macOS if one wants to install such a toolchain into Xcode:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;Untar and copy the toolchain to one of &lt;code&gt;/Library/Developer/Toolchains/&lt;/code&gt; or &lt;code&gt;~/Library/Developer/Toolchains/&lt;/code&gt;. E.g.:&lt;/li&gt; 
&lt;/ol&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;  $ sudo tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz -C /
  $ tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz -C ~/
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The script also generates an archive containing debug symbols which can be installed over the main archive allowing symbolication of any compiler crashes.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;  $ sudo tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx-symbols.tar.gz -C /
  $ tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx-symbols.tar.gz -C ~/
&lt;/code&gt;&lt;/pre&gt; 
&lt;ol start=&quot;2&quot;&gt; 
 &lt;li&gt;Specify the local toolchain for Xcode&#39;s use via &lt;code&gt;Xcode-&amp;gt;Toolchains&lt;/code&gt;.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h3&gt;Build Failures&lt;/h3&gt; 
&lt;p&gt;Try the suggestions in &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/GettingStarted.md#troubleshooting-build-issues&quot;&gt;Troubleshooting build issues&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Make sure you are using the &lt;a href=&quot;https://raw.githubusercontent.com/swiftlang/swift/main/docs/HowToGuides/GettingStarted.md#installing-dependencies&quot;&gt;correct release&lt;/a&gt; of Xcode.&lt;/p&gt; 
&lt;p&gt;If you have changed Xcode versions but still encounter errors that appear to be related to the Xcode version, try passing &lt;code&gt;--clean&lt;/code&gt; to &lt;code&gt;build-script&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;When a new version of Xcode is released, you can update your build without recompiling the entire project by passing &lt;code&gt;--reconfigure&lt;/code&gt; to &lt;code&gt;build-script&lt;/code&gt;.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/c5987c417cf7c26f013308b8eefb7236d81581912e6dc6d6ac2fe2ccd758cf29/swiftlang/swift" medium="image" />
      
    </item>
    
    <item>
      <title>groue/GRDB.swift</title>
      <link>https://github.com/groue/GRDB.swift</link>
      <description>&lt;p&gt;A toolkit for SQLite databases, with a focus on application development&lt;/p&gt;&lt;hr&gt;&lt;picture&gt; 
 &lt;source media=&quot;(prefers-color-scheme: dark)&quot; srcset=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/GRDB~dark.png&quot; /&gt; 
 &lt;source media=&quot;(prefers-color-scheme: light)&quot; srcset=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/GRDB.png&quot; /&gt; 
 &lt;img alt=&quot;GRDB: A toolkit for SQLite databases, with a focus on application development.&quot; src=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/GRDB.png&quot; /&gt; 
&lt;/picture&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;strong&gt;A toolkit for SQLite databases, with a focus on application development&lt;/strong&gt;&lt;br /&gt; Proudly serving the community since 2015 &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://developer.apple.com/swift/&quot;&gt;&lt;img alt=&quot;Swift 6.1&quot; src=&quot;https://img.shields.io/badge/swift-6.1-orange.svg?style=flat&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/groue/GRDB.swift/raw/master/LICENSE&quot;&gt;&lt;img alt=&quot;License&quot; src=&quot;https://img.shields.io/github/license/groue/GRDB.swift.svg?maxAge=2592000&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/groue/GRDB.swift/actions/workflows/CI.yml&quot;&gt;&lt;img alt=&quot;CI Status&quot; src=&quot;https://github.com/groue/GRDB.swift/actions/workflows/CI.yml/badge.svg?branch=master&quot; /&gt;&lt;/a&gt; &lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Latest release&lt;/strong&gt;: June 18, 2026 • &lt;a href=&quot;https://github.com/groue/GRDB.swift/tree/v7.11.1&quot;&gt;version 7.11.1&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/CHANGELOG.md&quot;&gt;CHANGELOG&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/GRDB7MigrationGuide.md&quot;&gt;Migrating From GRDB 6 to GRDB 7&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;: iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 7.0+ • SQLite 3.20.0+ • Swift 6.1+ / Xcode 16.3+&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Contact&lt;/strong&gt;:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Release announcements and usage tips: follow &lt;a href=&quot;https://hachyderm.io/@groue&quot;&gt;@groue@hachyderm.io&lt;/a&gt; on Mastodon.&lt;/li&gt; 
 &lt;li&gt;Report bugs in a &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues/new&quot;&gt;Github issue&lt;/a&gt;. Make sure you check the &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues?q=is%3Aopen&quot;&gt;existing issues&lt;/a&gt; first.&lt;/li&gt; 
 &lt;li&gt;A question? Looking for advice? Do you wonder how to contribute? Fancy a chat? Go to the &lt;a href=&quot;https://github.com/groue/GRDB.swift/discussions&quot;&gt;GitHub discussions&lt;/a&gt;, or the &lt;a href=&quot;https://forums.swift.org/c/related-projects/grdb&quot;&gt;GRDB forums&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;What is GRDB?&lt;/h2&gt; 
&lt;p&gt;Use this library to save your application’s permanent data into SQLite databases. It comes with built-in tools that address common needs:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;SQL Generation&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Enhance your application models with persistence and fetching methods, so that you don&#39;t have to deal with SQL and raw database rows when you don&#39;t want to.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Database Observation&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Get notifications when database values are modified.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Robust Concurrency&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Multi-threaded applications can efficiently use their databases, including WAL databases that support concurrent reads and writes.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Migrations&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Evolve the schema of your database as you ship new versions of your application.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Leverage your SQLite skills&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Not all developers need advanced SQLite features. But when you do, GRDB is as sharp as you want it to be. Come with your SQL and SQLite skills, or learn new ones as you go!&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;hr /&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#usage&quot;&gt;Usage&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#documentation&quot;&gt;Documentation&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#installation&quot;&gt;Installation&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt; &lt;/p&gt; 
&lt;hr /&gt; 
&lt;h2&gt;Usage&lt;/h2&gt; 
&lt;details open&gt; 
 &lt;summary&gt;Start using the database in four steps&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import GRDB

// 1. Open a database connection
let dbQueue = try DatabaseQueue(path: &quot;/path/to/database.sqlite&quot;)

// 2. Define the database schema
try dbQueue.write { db in
    try db.create(table: &quot;player&quot;) { t in
        t.primaryKey(&quot;id&quot;, .text)
        t.column(&quot;name&quot;, .text).notNull()
        t.column(&quot;score&quot;, .integer).notNull()
    }
}

// 3. Define a record type
struct Player: Codable, Identifiable, FetchableRecord, PersistableRecord {
    var id: String
    var name: String
    var score: Int
    
    enum Columns {
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}

// 4. Write and read in the database
try dbQueue.write { db in
    try Player(id: &quot;1&quot;, name: &quot;Arthur&quot;, score: 100).insert(db)
    try Player(id: &quot;2&quot;, name: &quot;Barbara&quot;, score: 1000).insert(db)
}

try dbQueue.read { db in
    let player = try Player.find(db, id: &quot;1&quot;)
    
    let bestPlayers = try Player
        .order(\.score.desc)
        .limit(10)
        .fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Access to raw SQL&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try db.execute(sql: &quot;&quot;&quot;
        CREATE TABLE player (
          id TEXT PRIMARY KEY,
          name TEXT NOT NULL,
          score INT NOT NULL)
        &quot;&quot;&quot;)
    
    try db.execute(sql: &quot;&quot;&quot;
        INSERT INTO player (id, name, score)
        VALUES (?, ?, ?)
        &quot;&quot;&quot;, arguments: [&quot;1&quot;, &quot;Arthur&quot;, 100])
    
    // Avoid SQL injection with SQL interpolation
    let id = &quot;2&quot;
    let name = &quot;O&#39;Brien&quot;
    let score = 1000
    try db.execute(literal: &quot;&quot;&quot;
        INSERT INTO player (id, name, score)
        VALUES (\(id), \(name), \(score))
        &quot;&quot;&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#executing-updates&quot;&gt;Executing Updates&lt;/a&gt;&lt;/p&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Access to raw database rows and values&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    // Fetch database rows
    let rows = try Row.fetchCursor(db, sql: &quot;SELECT * FROM player&quot;)
    while let row = try rows.next() {
        let id: String = row[&quot;id&quot;]
        let name: String = row[&quot;name&quot;]
        let score: Int = row[&quot;score&quot;]
    }
    
    // Fetch values
    let playerCount = try Int.fetchOne(db, sql: &quot;SELECT COUNT(*) FROM player&quot;)! // Int
    let playerNames = try String.fetchAll(db, sql: &quot;SELECT name FROM player&quot;) // [String]
}

let playerCount = try dbQueue.read { db in
    try Int.fetchOne(db, sql: &quot;SELECT COUNT(*) FROM player&quot;)!
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetch-queries&quot;&gt;Fetch Queries&lt;/a&gt;&lt;/p&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Database model types aka &quot;records&quot;&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Codable, Identifiable, FetchableRecord, PersistableRecord {
    var id: String
    var name: String
    var score: Int
    
    enum Columns {
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}

try dbQueue.write { db in
    // Create database table
    try db.create(table: &quot;player&quot;) { t in
        t.primaryKey(&quot;id&quot;, .text)
        t.column(&quot;name&quot;, .text).notNull()
        t.column(&quot;score&quot;, .integer).notNull()
    }
    
    // Insert a record
    var player = Player(id: &quot;1&quot;, name: &quot;Arthur&quot;, score: 100)
    try player.insert(db)
    
    // Update a record
    player.score += 10
    try player.update(db)
    
    try player.updateChanges { $0.score += 10 }
    
    // Delete a record
    try player.delete(db)
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;Records&lt;/a&gt;&lt;/p&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Query the database with the Swift query interface&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    // Player
    let player = try Player.find(db, id: &quot;1&quot;)
    
    // Player?
    let arthur = try Player.filter { $0.name == &quot;Arthur&quot; }.fetchOne(db)
    
    // [Player]
    let bestPlayers = try Player.order(\.score.desc).limit(10).fetchAll(db)
    
    // Int
    let playerCount = try Player.fetchCount(db)
    
    // SQL is always welcome
    let players = try Player.fetchAll(db, sql: &quot;SELECT * FROM player&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;Query Interface&lt;/a&gt;&lt;/p&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Database changes notifications&lt;/summary&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Define the observed value
let observation = ValueObservation.tracking { db in
    try Player.fetchAll(db)
}

// Start observation
let cancellable = observation.start(
    in: dbQueue,
    onError: { error in ... },
    onChange: { (players: [Player]) in print(&quot;Fresh players: \(players)&quot;) })
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;Ready-made support for Combine and RxSwift:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Swift concurrency
for try await players in observation.values(in: dbQueue) {
    print(&quot;Fresh players: \(players)&quot;)
}

// Combine
let cancellable = observation.publisher(in: dbQueue).sink(
    receiveCompletion: { completion in ... },
    receiveValue: { (players: [Player]) in print(&quot;Fresh players: \(players)&quot;) })

// RxSwift
let disposable = observation.rx.observe(in: dbQueue).subscribe(
    onNext: { (players: [Player]) in print(&quot;Fresh players: \(players)&quot;) },
    onError: { error in ... })
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseobservation&quot;&gt;Database Observation&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/Combine.md&quot;&gt;Combine Support&lt;/a&gt;, &lt;a href=&quot;https://github.com/RxSwiftCommunity/RxGRDB&quot;&gt;RxGRDB&lt;/a&gt;.&lt;/p&gt; 
&lt;/details&gt; 
&lt;h1&gt;Documentation&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;GRDB runs on top of SQLite&lt;/strong&gt;: you should get familiar with the &lt;a href=&quot;http://www.sqlite.org/faq.html&quot;&gt;SQLite FAQ&lt;/a&gt;. For general and detailed information, jump to the &lt;a href=&quot;http://www.sqlite.org/docs.html&quot;&gt;SQLite Documentation&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Demo Applications &amp;amp; Frequently Asked Questions&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/DemoApps&quot;&gt;Demo Applications&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Reference&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/&quot;&gt;GRDB Reference&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Getting Started&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#installation&quot;&gt;Installation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;Database Connections&lt;/a&gt;: Connect to SQLite databases&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;SQLite and SQL&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-api&quot;&gt;SQLite API&lt;/a&gt;: The low-level SQLite API • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#executing-updates&quot;&gt;executing updates&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetch-queries&quot;&gt;fetch queries&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Records and the Query Interface&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;Records&lt;/a&gt;: Fetching and persistence methods for your custom structs and class hierarchies&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;Query Interface&lt;/a&gt;: A swift way to generate SQL • &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseschema&quot;&gt;create tables, indexes, etc&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#requests&quot;&gt;requests&lt;/a&gt; • &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;associations between record types&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Application Tools&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/migrations&quot;&gt;Migrations&lt;/a&gt;: Transform your database as your application evolves.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md&quot;&gt;Full-Text Search&lt;/a&gt;: Perform efficient and customizable full-text searches.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseobservation&quot;&gt;Database Observation&lt;/a&gt;: Observe database changes and transactions.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#encryption&quot;&gt;Encryption&lt;/a&gt;: Encrypt your database with SQLCipher.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#backup&quot;&gt;Backup&lt;/a&gt;: Dump the content of a database to another.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#interrupt-a-database&quot;&gt;Interrupt a Database&lt;/a&gt;: Abort any pending database operation.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasesharing&quot;&gt;Sharing a Database&lt;/a&gt;: How to share an SQLite database between multiple processes - recommendations for App Group containers, App Extensions, App Sandbox, and file coordination.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Good to Know&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;Concurrency&lt;/a&gt;: How to access databases in a multi-threaded application.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/Combine.md&quot;&gt;Combine&lt;/a&gt;: Access and observe the database with Combine publishers.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#avoiding-sql-injection&quot;&gt;Avoiding SQL Injection&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#error-handling&quot;&gt;Error Handling&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#unicode&quot;&gt;Unicode&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#memory-management&quot;&gt;Memory Management&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseconnections&quot;&gt;Data Protection&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;💡 &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/GRDB7MigrationGuide.md&quot;&gt;Migrating From GRDB 6 to GRDB 7&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;💡 &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/WhyAdoptGRDB.md&quot;&gt;Why Adopt GRDB?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;💡 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recordrecommendedpractices&quot;&gt;Recommended Practices for Designing Record Types&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Companion Libraries&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/groue/GRDBQuery&quot;&gt;GRDBQuery&lt;/a&gt;: Access and observe the database from your SwiftUI views.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/groue/GRDBSnapshotTesting&quot;&gt;GRDBSnapshotTesting&lt;/a&gt;: Test your database.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sample-code&quot;&gt;Sample Code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;h1&gt;Installation&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;The installation procedures below have GRDB use the version of SQLite that ships with the target operating system.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#encryption&quot;&gt;Encryption&lt;/a&gt; for the installation procedure of GRDB with SQLCipher.&lt;/p&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CustomSQLiteBuilds.md&quot;&gt;Custom SQLite builds&lt;/a&gt; for the installation procedure of GRDB with a customized build of SQLite.&lt;/p&gt; 
&lt;h2&gt;Swift Package Manager&lt;/h2&gt; 
&lt;p&gt;The &lt;a href=&quot;https://swift.org/package-manager/&quot;&gt;Swift Package Manager&lt;/a&gt; automates the distribution of Swift code. To use GRDB with SPM, add a dependency to &lt;code&gt;https://github.com/groue/GRDB.swift.git&lt;/code&gt;&lt;/p&gt; 
&lt;p&gt;GRDB offers two libraries, &lt;code&gt;GRDB&lt;/code&gt; and &lt;code&gt;GRDB-dynamic&lt;/code&gt;. Pick only one. When in doubt, prefer &lt;code&gt;GRDB&lt;/code&gt;. The &lt;code&gt;GRDB-dynamic&lt;/code&gt; library can reveal useful if you are going to link it with multiple targets within your app and only wish to link to a shared, dynamic framework once. See &lt;a href=&quot;https://forums.swift.org/t/how-to-link-a-swift-package-as-dynamic/32062&quot;&gt;How to link a Swift Package as dynamic&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Linux support is provided by contributors. It is not automatically tested, and not officially maintained. If you notice a build or runtime failure on Linux, please open a pull request with the necessary fix, thank you!&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;CocoaPods&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;http://cocoapods.org/&quot;&gt;CocoaPods&lt;/a&gt; is a dependency manager for Xcode projects. To use GRDB with CocoaPods (version 1.2 or higher), specify in your &lt;code&gt;Podfile&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;pod &#39;GRDB.swift&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;GRDB can be installed as a framework, or a static library.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Important Note for CocoaPods installation&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Due to an &lt;a href=&quot;https://github.com/CocoaPods/CocoaPods/issues/11839&quot;&gt;issue&lt;/a&gt; in CocoaPods, it is currently not possible to deploy new versions of GRDB to CocoaPods. The last version available on CocoaPods is 6.24.1. To install later versions of GRDB using CocoaPods, use one of the following workarounds:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;Depend on the &lt;code&gt;GRDB7&lt;/code&gt; branch. This is more or less equivalent to what &lt;code&gt;pod &#39;GRDB.swift&#39;, &#39;~&amp;gt; 7.0&#39;&lt;/code&gt; would normally do, if CocoaPods would accept new GRDB versions to be published:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# Can&#39;t use semantic versioning due to https://github.com/CocoaPods/CocoaPods/issues/11839
pod &#39;GRDB.swift&#39;, git: &#39;https://github.com/groue/GRDB.swift.git&#39;, branch: &#39;GRDB7&#39;
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Depend on a specific version explicitly (Replace the tag with the version you want to use):&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# Can&#39;t use semantic versioning due to https://github.com/CocoaPods/CocoaPods/issues/11839
# Replace the tag with the tag that you want to use.
pod &#39;GRDB.swift&#39;, git: &#39;https://github.com/groue/GRDB.swift.git&#39;, tag: &#39;v6.29.0&#39; 
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Carthage&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/Carthage/Carthage&quot;&gt;Carthage&lt;/a&gt; is &lt;strong&gt;unsupported&lt;/strong&gt;. For some context about this decision, see &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues/433&quot;&gt;#433&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Manually&lt;/h2&gt; 
&lt;ol&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://github.com/groue/GRDB.swift/releases&quot;&gt;Download&lt;/a&gt; a copy of GRDB, or clone its repository and make sure you checkout the latest tagged version.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Embed the &lt;code&gt;GRDB.xcodeproj&lt;/code&gt; project in your own project.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Add the &lt;code&gt;GRDB&lt;/code&gt; target in the &lt;strong&gt;Target Dependencies&lt;/strong&gt; section of the &lt;strong&gt;Build Phases&lt;/strong&gt; tab of your application target (extension target for WatchOS).&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Add the &lt;code&gt;GRDB.framework&lt;/code&gt; to the &lt;strong&gt;Embedded Binaries&lt;/strong&gt; section of the &lt;strong&gt;General&lt;/strong&gt; tab of your application target (extension target for WatchOS).&lt;/p&gt; &lt;/li&gt; 
&lt;/ol&gt; 
&lt;h1&gt;Database Connections&lt;/h1&gt; 
&lt;p&gt;GRDB provides two classes for accessing SQLite databases: &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasequeue&quot;&gt;&lt;code&gt;DatabaseQueue&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;&lt;code&gt;DatabasePool&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import GRDB

// Pick one:
let dbQueue = try DatabaseQueue(path: &quot;/path/to/database.sqlite&quot;)
let dbPool = try DatabasePool(path: &quot;/path/to/database.sqlite&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The differences are:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Database pools allow concurrent database accesses (this can improve the performance of multithreaded applications).&lt;/li&gt; 
 &lt;li&gt;Database pools open your SQLite database in the &lt;a href=&quot;https://www.sqlite.org/wal.html&quot;&gt;WAL mode&lt;/a&gt; (unless read-only).&lt;/li&gt; 
 &lt;li&gt;Database queues support &lt;a href=&quot;https://www.sqlite.org/inmemorydb.html&quot;&gt;in-memory databases&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;If you are not sure, choose &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasequeue&quot;&gt;&lt;code&gt;DatabaseQueue&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; You will always be able to switch to &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;&lt;code&gt;DatabasePool&lt;/code&gt;&lt;/a&gt; later.&lt;/p&gt; 
&lt;p&gt;For more information and tips when opening connections, see &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseconnections&quot;&gt;Database Connections&lt;/a&gt;.&lt;/p&gt; 
&lt;h1&gt;SQLite API&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;In this section of the documentation, we will talk SQL.&lt;/strong&gt; Jump to the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt; if SQL is not your cup of tea.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#executing-updates&quot;&gt;Executing Updates&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetch-queries&quot;&gt;Fetch Queries&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;Fetching Methods&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#row-queries&quot;&gt;Row Queries&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#value-queries&quot;&gt;Value Queries&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#data-and-memory-savings&quot;&gt;Data&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date-and-datecomponents&quot;&gt;Date and DateComponents&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#nsnumber-nsdecimalnumber-and-decimal&quot;&gt;NSNumber, NSDecimalNumber, and Decimal&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#swift-enums&quot;&gt;Swift enums&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt;: the protocol for custom value types&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/transactions&quot;&gt;Transactions and Savepoints&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Advanced topics:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;Prepared Statements&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-sql-functions-and-aggregates&quot;&gt;Custom SQL Functions and Aggregates&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseschemaintrospection&quot;&gt;Database Schema Introspection&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/rowadapter&quot;&gt;Row Adapters&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#raw-sqlite-pointers&quot;&gt;Raw SQLite Pointers&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Executing Updates&lt;/h2&gt; 
&lt;p&gt;Once granted with a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;database connection&lt;/a&gt;, the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/execute(sql:arguments:)&quot;&gt;&lt;code&gt;execute(sql:arguments:)&lt;/code&gt;&lt;/a&gt; method executes the SQL statements that do not return any database row, such as &lt;code&gt;CREATE TABLE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;ALTER&lt;/code&gt;, etc.&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try db.execute(sql: &quot;&quot;&quot;
        CREATE TABLE player (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            score INT)
        &quot;&quot;&quot;)
    
    try db.execute(
        sql: &quot;INSERT INTO player (name, score) VALUES (?, ?)&quot;,
        arguments: [&quot;Barbara&quot;, 1000])
    
    try db.execute(
        sql: &quot;UPDATE player SET score = :score WHERE id = :id&quot;,
        arguments: [&quot;score&quot;: 1000, &quot;id&quot;: 1])
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;?&lt;/code&gt; and colon-prefixed keys like &lt;code&gt;:score&lt;/code&gt; in the SQL query are the &lt;strong&gt;statements arguments&lt;/strong&gt;. You pass arguments with arrays or dictionaries, as in the example above. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information on supported arguments types (Bool, Int, String, Date, Swift enums, etc.), and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statementarguments&quot;&gt;&lt;code&gt;StatementArguments&lt;/code&gt;&lt;/a&gt; for a detailed documentation of SQLite arguments.&lt;/p&gt; 
&lt;p&gt;You can also embed query arguments right into your SQL queries, with &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/execute(literal:)&quot;&gt;&lt;code&gt;execute(literal:)&lt;/code&gt;&lt;/a&gt;, as in the example below. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt; for more details.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    let name = &quot;O&#39;Brien&quot;
    let score = 550
    try db.execute(literal: &quot;&quot;&quot;
        INSERT INTO player (name, score) VALUES (\(name), \(score))
        &quot;&quot;&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Never ever embed values directly in your raw SQL strings&lt;/strong&gt;. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#avoiding-sql-injection&quot;&gt;Avoiding SQL Injection&lt;/a&gt; for more information:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// WRONG: don&#39;t embed values in raw SQL strings
let id = 123
let name = textField.text
try db.execute(
    sql: &quot;UPDATE player SET name = &#39;\(name)&#39; WHERE id = \(id)&quot;)

// CORRECT: use arguments dictionary
try db.execute(
    sql: &quot;UPDATE player SET name = :name WHERE id = :id&quot;,
    arguments: [&quot;name&quot;: name, &quot;id&quot;: id])

// CORRECT: use arguments array
try db.execute(
    sql: &quot;UPDATE player SET name = ? WHERE id = ?&quot;,
    arguments: [name, id])

// CORRECT: use SQL Interpolation
try db.execute(
    literal: &quot;UPDATE player SET name = \(name) WHERE id = \(id)&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Join multiple statements with a semicolon&lt;/strong&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try db.execute(sql: &quot;&quot;&quot;
    INSERT INTO player (name, score) VALUES (?, ?);
    INSERT INTO player (name, score) VALUES (?, ?);
    &quot;&quot;&quot;, arguments: [&quot;Arthur&quot;, 750, &quot;Barbara&quot;, 1000])

try db.execute(literal: &quot;&quot;&quot;
    INSERT INTO player (name, score) VALUES (\(&quot;Arthur&quot;), \(750));
    INSERT INTO player (name, score) VALUES (\(&quot;Barbara&quot;), \(1000));
    &quot;&quot;&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When you want to make sure that a single statement is executed, use a prepared &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;&lt;code&gt;Statement&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;After an INSERT statement&lt;/strong&gt;, you can get the row ID of the inserted row with &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/lastinsertedrowid&quot;&gt;&lt;code&gt;lastInsertedRowID&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try db.execute(
    sql: &quot;INSERT INTO player (name, score) VALUES (?, ?)&quot;,
    arguments: [&quot;Arthur&quot;, 1000])
let playerId = db.lastInsertedRowID
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Don&#39;t miss &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;Records&lt;/a&gt;, that provide classic &lt;strong&gt;persistence methods&lt;/strong&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var player = Player(name: &quot;Arthur&quot;, score: 1000)
try player.insert(db)
let playerId = player.id
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Fetch Queries&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;Database connections&lt;/a&gt; let you fetch database rows, plain values, and custom models aka &quot;records&quot;.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Rows&lt;/strong&gt; are the raw results of SQL queries:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    if let row = try Row.fetchOne(db, sql: &quot;SELECT * FROM wine WHERE id = ?&quot;, arguments: [1]) {
        let name: String = row[&quot;name&quot;]
        let color: Color = row[&quot;color&quot;]
        print(name, color)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Values&lt;/strong&gt; are the Bool, Int, String, Date, Swift enums, etc. stored in row columns:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    let urls = try URL.fetchCursor(db, sql: &quot;SELECT url FROM wine&quot;)
    while let url = try urls.next() {
        print(url)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Records&lt;/strong&gt; are your application objects that can initialize themselves from rows:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let wines = try dbQueue.read { db in
    try Wine.fetchAll(db, sql: &quot;SELECT * FROM wine&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;Fetching Methods&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#cursors&quot;&gt;Cursors&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#row-queries&quot;&gt;Row Queries&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#value-queries&quot;&gt;Value Queries&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;Records&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Fetching Methods&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Throughout GRDB&lt;/strong&gt;, you can always fetch &lt;em&gt;cursors&lt;/em&gt;, &lt;em&gt;arrays&lt;/em&gt;, &lt;em&gt;sets&lt;/em&gt;, or &lt;em&gt;single values&lt;/em&gt; of any fetchable type (database &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#row-queries&quot;&gt;row&lt;/a&gt;, simple &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#value-queries&quot;&gt;value&lt;/a&gt;, or custom &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;record&lt;/a&gt;):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Row.fetchCursor(...) // A Cursor of Row
try Row.fetchAll(...)    // [Row]
try Row.fetchSet(...)    // Set&amp;lt;Row&amp;gt;
try Row.fetchOne(...)    // Row?
&lt;/code&gt;&lt;/pre&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;fetchCursor&lt;/code&gt; returns a &lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#cursors&quot;&gt;cursor&lt;/a&gt;&lt;/strong&gt; over fetched values:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let rows = try Row.fetchCursor(db, sql: &quot;SELECT ...&quot;) // A Cursor of Row
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;fetchAll&lt;/code&gt; returns an &lt;strong&gt;array&lt;/strong&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let players = try Player.fetchAll(db, sql: &quot;SELECT ...&quot;) // [Player]
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;fetchSet&lt;/code&gt; returns a &lt;strong&gt;set&lt;/strong&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let names = try String.fetchSet(db, sql: &quot;SELECT ...&quot;) // Set&amp;lt;String&amp;gt;
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;fetchOne&lt;/code&gt; returns a &lt;strong&gt;single optional value&lt;/strong&gt;, and consumes a single database row (if any).&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let count = try Int.fetchOne(db, sql: &quot;SELECT COUNT(*) ...&quot;) // Int?
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;All those fetching methods require an SQL string that contains a single SQL statement.&lt;/strong&gt; When you want to fetch from multiple statements joined with a semicolon, iterate the multiple &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;prepared statements&lt;/a&gt; found in the SQL string.&lt;/p&gt; 
&lt;h3&gt;Cursors&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/cursor&quot;&gt;&lt;code&gt;Cursor&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Whenever you consume several rows from the database, you can fetch an Array, a Set, or a Cursor&lt;/strong&gt;.&lt;/p&gt; 
&lt;p&gt;The &lt;code&gt;fetchAll()&lt;/code&gt; and &lt;code&gt;fetchSet()&lt;/code&gt; methods return regular Swift array and sets, that you iterate like all other arrays and sets:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    // [Player]
    let players = try Player.fetchAll(db, sql: &quot;SELECT ...&quot;)
    for player in players {
        // use player
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Unlike arrays and sets, cursors returned by &lt;code&gt;fetchCursor()&lt;/code&gt; load their results step after step:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    // Cursor of Player
    let players = try Player.fetchCursor(db, sql: &quot;SELECT ...&quot;)
    while let player = try players.next() {
        // use player
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors can not be used on any thread&lt;/strong&gt;: you must consume a cursor on the dispatch queue it was created in. Particularly, don&#39;t extract a cursor out of a database access method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Wrong
let cursor = try dbQueue.read { db in
    try Player.fetchCursor(db, ...)
}
while let player = try cursor.next() { ... }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Conversely, arrays and sets may be consumed on any thread:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// OK
let array = try dbQueue.read { db in
    try Player.fetchAll(db, ...)
}
for player in array { ... }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors can be iterated only one time.&lt;/strong&gt; Arrays and sets can be iterated many times.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors iterate database results in a lazy fashion&lt;/strong&gt;, and don&#39;t consume much memory. Arrays and sets contain copies of database values, and may take a lot of memory when there are many fetched results.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors are granted with direct access to SQLite,&lt;/strong&gt; unlike arrays and sets that have to take the time to copy database values. If you look after extra performance, you may prefer cursors.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors can feed Swift collections.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;You will most of the time use &lt;code&gt;fetchAll&lt;/code&gt; or &lt;code&gt;fetchSet&lt;/code&gt; when you want an array or a set. For more specific needs, you may prefer one of the initializers below. All of them accept an extra optional &lt;code&gt;minimumCapacity&lt;/code&gt; argument which helps optimizing your app when you have an idea of the number of elements in a cursor (the built-in &lt;code&gt;fetchAll&lt;/code&gt; and &lt;code&gt;fetchSet&lt;/code&gt; do not perform such an optimization).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Arrays&lt;/strong&gt; and all types conforming to &lt;code&gt;RangeReplaceableCollection&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// [String]
let cursor = try String.fetchCursor(db, ...)
let array = try Array(cursor)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;Sets&lt;/strong&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Set&amp;lt;Int&amp;gt;
let cursor = try Int.fetchCursor(db, ...)
let set = try Set(cursor)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;Dictionaries&lt;/strong&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// [Int64: [Player]]
let cursor = try Player.fetchCursor(db)
let dictionary = try Dictionary(grouping: cursor, by: { $0.teamID })

// [Int64: Player]
let cursor = try Player.fetchCursor(db).map { ($0.id, $0) }
let dictionary = try Dictionary(uniqueKeysWithValues: cursor)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors adopt the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/cursor&quot;&gt;Cursor&lt;/a&gt; protocol, which looks a lot like standard &lt;a href=&quot;https://developer.apple.com/reference/swift/lazysequenceprotocol&quot;&gt;lazy sequences&lt;/a&gt; of Swift.&lt;/strong&gt; As such, cursors come with many convenience methods: &lt;code&gt;compactMap&lt;/code&gt;, &lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;dropFirst&lt;/code&gt;, &lt;code&gt;dropLast&lt;/code&gt;, &lt;code&gt;drop(while:)&lt;/code&gt;, &lt;code&gt;enumerated&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt;, &lt;code&gt;joined&lt;/code&gt;, &lt;code&gt;joined(separator:)&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;max(by:)&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;min(by:)&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;prefix&lt;/code&gt;, &lt;code&gt;prefix(while:)&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;reduce(into:)&lt;/code&gt;, &lt;code&gt;suffix&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Prints all Github links
try URL
    .fetchCursor(db, sql: &quot;SELECT url FROM link&quot;)
    .filter { url in url.host == &quot;github.com&quot; }
    .forEach { url in print(url) }

// An efficient cursor of coordinates:
let locations = try Row.
    .fetchCursor(db, sql: &quot;SELECT latitude, longitude FROM place&quot;)
    .map { row in
        CLLocationCoordinate2D(latitude: row[0], longitude: row[1])
    }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors are not Swift sequences.&lt;/strong&gt; That&#39;s because Swift sequences can&#39;t handle iteration errors, when reading SQLite results may fail at any time.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Cursors require a little care&lt;/strong&gt;:&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt; &lt;p&gt;Don&#39;t modify the results during a cursor iteration:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Undefined behavior
while let player = try players.next() {
    try db.execute(sql: &quot;DELETE ...&quot;)
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
   &lt;li&gt; &lt;p&gt;Don&#39;t turn a cursor of &lt;code&gt;Row&lt;/code&gt; into an array or a set. You would not get the distinct rows you expect. To get a array of rows, use &lt;code&gt;Row.fetchAll(...)&lt;/code&gt;. To get a set of rows, use &lt;code&gt;Row.fetchSet(...)&lt;/code&gt;. Generally speaking, make sure you copy a row whenever you extract it from a cursor for later use: &lt;code&gt;row.copy()&lt;/code&gt;.&lt;/p&gt; &lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;If you don&#39;t see, or don&#39;t care about the difference, use arrays. If you care about memory and performance, use cursors when appropriate.&lt;/p&gt; 
&lt;h3&gt;Row Queries&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-rows&quot;&gt;Fetching Rows&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#column-values&quot;&gt;Column Values&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#rows-as-dictionaries&quot;&gt;Rows as Dictionaries&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/row&quot;&gt;&lt;code&gt;Row&lt;/code&gt;&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Fetching Rows&lt;/h4&gt; 
&lt;p&gt;Fetch &lt;strong&gt;cursors&lt;/strong&gt; of rows, &lt;strong&gt;arrays&lt;/strong&gt;, &lt;strong&gt;sets&lt;/strong&gt;, or &lt;strong&gt;single&lt;/strong&gt; rows (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;fetching methods&lt;/a&gt;):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    try Row.fetchCursor(db, sql: &quot;SELECT ...&quot;, arguments: ...) // A Cursor of Row
    try Row.fetchAll(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // [Row]
    try Row.fetchSet(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // Set&amp;lt;Row&amp;gt;
    try Row.fetchOne(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // Row?
    
    let rows = try Row.fetchCursor(db, sql: &quot;SELECT * FROM wine&quot;)
    while let row = try rows.next() {
        let name: String = row[&quot;name&quot;]
        let color: Color = row[&quot;color&quot;]
        print(name, color)
    }
}

let rows = try dbQueue.read { db in
    try Row.fetchAll(db, sql: &quot;SELECT * FROM player&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Arguments are optional arrays or dictionaries that fill the positional &lt;code&gt;?&lt;/code&gt; and colon-prefixed keys like &lt;code&gt;:name&lt;/code&gt; in the query:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let rows = try Row.fetchAll(db,
    sql: &quot;SELECT * FROM player WHERE name = ?&quot;,
    arguments: [&quot;Arthur&quot;])

let rows = try Row.fetchAll(db,
    sql: &quot;SELECT * FROM player WHERE name = :name&quot;,
    arguments: [&quot;name&quot;: &quot;Arthur&quot;])
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information on supported arguments types (Bool, Int, String, Date, Swift enums, etc.), and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statementarguments&quot;&gt;&lt;code&gt;StatementArguments&lt;/code&gt;&lt;/a&gt; for a detailed documentation of SQLite arguments.&lt;/p&gt; 
&lt;p&gt;Unlike row arrays that contain copies of the database rows, row cursors are close to the SQLite metal, and require a little care:&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;strong&gt;Don&#39;t turn a cursor of &lt;code&gt;Row&lt;/code&gt; into an array or a set&lt;/strong&gt;. You would not get the distinct rows you expect. To get a array of rows, use &lt;code&gt;Row.fetchAll(...)&lt;/code&gt;. To get a set of rows, use &lt;code&gt;Row.fetchSet(...)&lt;/code&gt;. Generally speaking, make sure you copy a row whenever you extract it from a cursor for later use: &lt;code&gt;row.copy()&lt;/code&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h4&gt;Column Values&lt;/h4&gt; 
&lt;p&gt;&lt;strong&gt;Read column values&lt;/strong&gt; by index or column name:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String = row[0]      // 0 is the leftmost column
let name: String = row[&quot;name&quot;] // Leftmost matching column - lookup is case-insensitive
let name: String = row[Column(&quot;name&quot;)] // Using query interface&#39;s Column
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Make sure to ask for an optional when the value may be NULL:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String? = row[&quot;name&quot;]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;row[]&lt;/code&gt; subscript returns the type you ask for. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information on supported value types:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let bookCount: Int     = row[&quot;bookCount&quot;]
let bookCount64: Int64 = row[&quot;bookCount&quot;]
let hasBooks: Bool     = row[&quot;bookCount&quot;] // false when 0

let string: String     = row[&quot;date&quot;]      // &quot;2015-09-11 18:14:15.123&quot;
let date: Date         = row[&quot;date&quot;]      // Date
self.date = row[&quot;date&quot;] // Depends on the type of the property.
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also use the &lt;code&gt;as&lt;/code&gt; type casting operator:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;row[...] as Int
row[...] as Int?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Throwing accessors exist as well. Their use is not encouraged, because a database decoding error is a programming error. If an application stores invalid data in the database file, that is a bug that needs to be fixed:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name = try row.decode(String.self, atIndex: 0)
let bookCount = try row.decode(Int.self, forColumn: &quot;bookCount&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: avoid the &lt;code&gt;as!&lt;/code&gt; and &lt;code&gt;as?&lt;/code&gt; operators:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;if let int = row[...] as? Int { ... } // BAD - doesn&#39;t work
if let int = row[...] as Int? { ... } // GOOD
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: avoid nil-coalescing row values, and prefer the &lt;code&gt;coalesce&lt;/code&gt; method instead:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String? = row[&quot;nickname&quot;] ?? row[&quot;name&quot;]     // BAD - doesn&#39;t work
let name: String? = row.coalesce([&quot;nickname&quot;, &quot;name&quot;]) // GOOD
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;Generally speaking, you can extract the type you need, provided it can be converted from the underlying SQLite value:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Successful conversions include:&lt;/strong&gt;&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt;All numeric SQLite values to all numeric Swift types, and Bool (zero is the only false boolean).&lt;/li&gt; 
   &lt;li&gt;Text SQLite values to Swift String.&lt;/li&gt; 
   &lt;li&gt;Blob SQLite values to Foundation Data.&lt;/li&gt; 
  &lt;/ul&gt; &lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information on supported types (Bool, Int, String, Date, Swift enums, etc.)&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;NULL returns nil.&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT NULL&quot;)!
row[0] as Int? // nil
row[0] as Int  // fatal error: could not convert NULL to Int.
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;There is one exception, though: the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; type:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;row[0] as DatabaseValue // DatabaseValue.null
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Missing columns return nil.&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT &#39;foo&#39; AS foo&quot;)!
row[&quot;missing&quot;] as String? // nil
row[&quot;missing&quot;] as String  // fatal error: no such column: missing
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;You can explicitly check for a column presence with the &lt;code&gt;hasColumn&lt;/code&gt; method.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Invalid conversions throw a fatal error.&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT &#39;Mom’s birthday&#39;&quot;)!
row[0] as String // &quot;Mom’s birthday&quot;
row[0] as Date?  // fatal error: could not convert &quot;Mom’s birthday&quot; to Date.
row[0] as Date   // fatal error: could not convert &quot;Mom’s birthday&quot; to Date.

let row = try Row.fetchOne(db, sql: &quot;SELECT 256&quot;)!
row[0] as Int    // 256
row[0] as UInt8? // fatal error: could not convert 256 to UInt8.
row[0] as UInt8  // fatal error: could not convert 256 to UInt8.
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Those conversion fatal errors can be avoided with the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; type:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT &#39;Mom’s birthday&#39;&quot;)!
let dbValue: DatabaseValue = row[0]
if dbValue.isNull {
    // Handle NULL
} else if let date = Date.fromDatabaseValue(dbValue) {
    // Handle valid date
} else {
    // Handle invalid date
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This extra verbosity is the consequence of having to deal with an untrusted database: you may consider fixing the content of your database instead. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fatal-errors&quot;&gt;Fatal Errors&lt;/a&gt; for more information.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;SQLite has a weak type system, and provides &lt;a href=&quot;https://www.sqlite.org/c3ref/column_blob.html&quot;&gt;convenience conversions&lt;/a&gt; that can turn String to Int, Double to Blob, etc.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;GRDB will sometimes let those conversions go through:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let rows = try Row.fetchCursor(db, sql: &quot;SELECT &#39;20 small cigars&#39;&quot;)
while let row = try rows.next() {
    row[0] as Int   // 20
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Don&#39;t freak out: those conversions did not prevent SQLite from becoming the immensely successful database engine you want to use. And GRDB adds safety checks described just above. You can also prevent those convenience conversions altogether by using the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; type.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;DatabaseValue&lt;/h4&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalue&quot;&gt;&lt;code&gt;DatabaseValue&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;code&gt;DatabaseValue&lt;/code&gt; is an intermediate type between SQLite and your values, which gives information about the raw value stored in the database.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;You get &lt;code&gt;DatabaseValue&lt;/code&gt; just like other value types:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dbValue: DatabaseValue = row[0]
let dbValue: DatabaseValue? = row[&quot;name&quot;] // nil if and only if column does not exist

// Check for NULL:
dbValue.isNull // Bool

// The stored value:
dbValue.storage.value // Int64, Double, String, Data, or nil

// All the five storage classes supported by SQLite:
switch dbValue.storage {
case .null:                 print(&quot;NULL&quot;)
case .int64(let int64):     print(&quot;Int64: \(int64)&quot;)
case .double(let double):   print(&quot;Double: \(double)&quot;)
case .string(let string):   print(&quot;String: \(string)&quot;)
case .blob(let data):       print(&quot;Data: \(data)&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can extract regular &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.) from &lt;code&gt;DatabaseValue&lt;/code&gt; with the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible/fromdatabasevalue(_:)-21zzv&quot;&gt;fromDatabaseValue()&lt;/a&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dbValue: DatabaseValue = row[&quot;bookCount&quot;]
let bookCount   = Int.fromDatabaseValue(dbValue)   // Int?
let bookCount64 = Int64.fromDatabaseValue(dbValue) // Int64?
let hasBooks    = Bool.fromDatabaseValue(dbValue)  // Bool?, false when 0

let dbValue: DatabaseValue = row[&quot;date&quot;]
let string = String.fromDatabaseValue(dbValue)     // &quot;2015-09-11 18:14:15.123&quot;
let date   = Date.fromDatabaseValue(dbValue)       // Date?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;code&gt;fromDatabaseValue&lt;/code&gt; returns nil for invalid conversions:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT &#39;Mom’s birthday&#39;&quot;)!
let dbValue: DatabaseValue = row[0]
let string = String.fromDatabaseValue(dbValue) // &quot;Mom’s birthday&quot;
let int    = Int.fromDatabaseValue(dbValue)    // nil
let date   = Date.fromDatabaseValue(dbValue)   // nil
&lt;/code&gt;&lt;/pre&gt; 
&lt;h4&gt;Rows as Dictionaries&lt;/h4&gt; 
&lt;p&gt;Row adopts the standard &lt;a href=&quot;https://developer.apple.com/documentation/swift/randomaccesscollection&quot;&gt;RandomAccessCollection&lt;/a&gt; protocol, and can be seen as a dictionary of &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// All the (columnName, dbValue) tuples, from left to right:
for (columnName, dbValue) in row {
    ...
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;You can build rows from dictionaries&lt;/strong&gt; (standard Swift dictionaries and NSDictionary). See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information on supported types:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row: Row = [&quot;name&quot;: &quot;foo&quot;, &quot;date&quot;: nil]
let row = Row([&quot;name&quot;: &quot;foo&quot;, &quot;date&quot;: nil])
let row = Row(/* [AnyHashable: Any] */) // nil if invalid dictionary
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Yet rows are not real dictionaries: they may contain duplicate columns:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT 1 AS foo, 2 AS foo&quot;)!
row.columnNames    // [&quot;foo&quot;, &quot;foo&quot;]
row.databaseValues // [1, 2]
row[&quot;foo&quot;]         // 1 (leftmost matching column)
for (columnName, dbValue) in row { ... } // (&quot;foo&quot;, 1), (&quot;foo&quot;, 2)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;When you build a dictionary from a row&lt;/strong&gt;, you have to disambiguate identical columns, and choose how to present database values. For example:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;A &lt;code&gt;[String: DatabaseValue]&lt;/code&gt; dictionary that keeps leftmost value in case of duplicated column name:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dict = Dictionary(row, uniquingKeysWith: { (left, _) in left })
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;A &lt;code&gt;[String: AnyObject]&lt;/code&gt; dictionary which keeps rightmost value in case of duplicated column name. This dictionary is identical to FMResultSet&#39;s resultDictionary from FMDB. It contains NSNull values for null columns, and can be shared with Objective-C:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dict = Dictionary(
    row.map { (column, dbValue) in
        (column, dbValue.storage.value as AnyObject)
    },
    uniquingKeysWith: { (_, right) in right })
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;A &lt;code&gt;[String: Any]&lt;/code&gt; dictionary that can feed, for example, JSONSerialization:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dict = Dictionary(
    row.map { (column, dbValue) in
        (column, dbValue.storage.value)
    },
    uniquingKeysWith: { (left, _) in left })
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;See the documentation of &lt;a href=&quot;https://developer.apple.com/documentation/swift/dictionary/2892961-init&quot;&gt;&lt;code&gt;Dictionary.init(_:uniquingKeysWith:)&lt;/code&gt;&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;h3&gt;Value Queries&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Instead of rows, you can directly fetch values.&lt;/strong&gt; There are many supported &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;value types&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.).&lt;/p&gt; 
&lt;p&gt;Like rows, fetch values as &lt;strong&gt;cursors&lt;/strong&gt;, &lt;strong&gt;arrays&lt;/strong&gt;, &lt;strong&gt;sets&lt;/strong&gt;, or &lt;strong&gt;single&lt;/strong&gt; values (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;fetching methods&lt;/a&gt;). Values are extracted from the leftmost column of the SQL queries:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    try Int.fetchCursor(db, sql: &quot;SELECT ...&quot;, arguments: ...) // A Cursor of Int
    try Int.fetchAll(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // [Int]
    try Int.fetchSet(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // Set&amp;lt;Int&amp;gt;
    try Int.fetchOne(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // Int?
    
    let maxScore = try Int.fetchOne(db, sql: &quot;SELECT MAX(score) FROM player&quot;) // Int?
    let names = try String.fetchAll(db, sql: &quot;SELECT name FROM player&quot;)       // [String]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;code&gt;Int.fetchOne&lt;/code&gt; returns nil in two cases: either the SELECT statement yielded no row, or one row with a NULL value:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// No row:
try Int.fetchOne(db, sql: &quot;SELECT 42 WHERE FALSE&quot;) // nil

// One row with a NULL value:
try Int.fetchOne(db, sql: &quot;SELECT NULL&quot;)           // nil

// One row with a non-NULL value:
try Int.fetchOne(db, sql: &quot;SELECT 42&quot;)             // 42
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For requests which may contain NULL, fetch optionals:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    try Optional&amp;lt;Int&amp;gt;.fetchCursor(db, sql: &quot;SELECT ...&quot;, arguments: ...) // A Cursor of Int?
    try Optional&amp;lt;Int&amp;gt;.fetchAll(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // [Int?]
    try Optional&amp;lt;Int&amp;gt;.fetchSet(db, sql: &quot;SELECT ...&quot;, arguments: ...)    // Set&amp;lt;Int?&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;: One advanced use case, when you fetch one value, is to distinguish the cases of a statement that yields no row, or one row with a NULL value. To do so, use &lt;code&gt;Optional&amp;lt;Int&amp;gt;.fetchOne&lt;/code&gt;, which returns a double optional &lt;code&gt;Int??&lt;/code&gt;:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// No row:
try Optional&amp;lt;Int&amp;gt;.fetchOne(db, sql: &quot;SELECT 42 WHERE FALSE&quot;) // .none
// One row with a NULL value:
try Optional&amp;lt;Int&amp;gt;.fetchOne(db, sql: &quot;SELECT NULL&quot;)           // .some(.none)
// One row with a non-NULL value:
try Optional&amp;lt;Int&amp;gt;.fetchOne(db, sql: &quot;SELECT 42&quot;)             // .some(.some(42))
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;There are many supported value types (Bool, Int, String, Date, Swift enums, etc.). See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;Values&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;h2&gt;Values&lt;/h2&gt; 
&lt;p&gt;GRDB ships with built-in support for the following value types:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Swift Standard Library&lt;/strong&gt;: Bool, Double, Float, all signed and unsigned integer types, String, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#swift-enums&quot;&gt;Swift enums&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Foundation&lt;/strong&gt;: &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#data-and-memory-savings&quot;&gt;Data&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date-and-datecomponents&quot;&gt;Date&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date-and-datecomponents&quot;&gt;DateComponents&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#nsnumber-nsdecimalnumber-and-decimal&quot;&gt;Decimal&lt;/a&gt;, NSNull, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#nsnumber-nsdecimalnumber-and-decimal&quot;&gt;NSNumber&lt;/a&gt;, NSString, URL, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#uuid&quot;&gt;UUID&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;CoreGraphics&lt;/strong&gt;: CGFloat.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt;&lt;/strong&gt;, the type which gives information about the raw value stored in the database.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Full-Text Patterns&lt;/strong&gt;: &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md#fts3pattern&quot;&gt;FTS3Pattern&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md#fts5pattern&quot;&gt;FTS5Pattern&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Generally speaking, all types that adopt the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt; protocol.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Values can be used as &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statementarguments&quot;&gt;statement arguments&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let url: URL = ...
let verified: Bool = ...
try db.execute(
    sql: &quot;INSERT INTO link (url, verified) VALUES (?, ?)&quot;,
    arguments: [url, verified])
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Values can be &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#column-values&quot;&gt;extracted from rows&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let rows = try Row.fetchCursor(db, sql: &quot;SELECT * FROM link&quot;)
while let row = try rows.next() {
    let url: URL = row[&quot;url&quot;]
    let verified: Bool = row[&quot;verified&quot;]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Values can be &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#value-queries&quot;&gt;directly fetched&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let urls = try URL.fetchAll(db, sql: &quot;SELECT url FROM link&quot;)  // [URL]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Use values in &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;Records&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Link: FetchableRecord {
    var url: URL
    var isVerified: Bool
    
    init(row: Row) {
        url = row[&quot;url&quot;]
        isVerified = row[&quot;verified&quot;]
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Use values in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let url: URL = ...
let link = try Link.filter { $0.url == url }.fetchOne(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Data (and Memory Savings)&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt; suits the BLOB SQLite columns. It can be stored and fetched from the database just like other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let rows = try Row.fetchCursor(db, sql: &quot;SELECT data, ...&quot;)
while let row = try rows.next() {
    let data: Data = row[&quot;data&quot;]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;At each step of the request iteration, the &lt;code&gt;row[]&lt;/code&gt; subscript creates &lt;em&gt;two copies&lt;/em&gt; of the database bytes: one fetched by SQLite, and another, stored in the Swift Data value.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;You have the opportunity to save memory&lt;/strong&gt; by not copying the data fetched by SQLite:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;while let row = try rows.next() {
    try row.withUnsafeData(name: &quot;data&quot;) { (data: Data?) in
        ...
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The non-copied data does not live longer than the iteration step: make sure that you do not use it past this point.&lt;/p&gt; 
&lt;h3&gt;Date and DateComponents&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date&quot;&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#datecomponents&quot;&gt;&lt;strong&gt;DateComponents&lt;/strong&gt;&lt;/a&gt; can be stored and fetched from the database.&lt;/p&gt; 
&lt;p&gt;Here is how GRDB supports the various &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;date formats&lt;/a&gt; supported by SQLite:&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th style=&quot;text-align:left&quot;&gt;SQLite format&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;Date&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;DateComponents&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD HH:MM&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ²&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD HH:MM:SS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ²&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD HH:MM:SS.SSS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ² / Write ¹&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD&lt;strong&gt;T&lt;/strong&gt;HH:MM&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ²&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ²&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD&lt;strong&gt;T&lt;/strong&gt;HH:MM:SS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ²&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ²&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;YYYY-MM-DD&lt;strong&gt;T&lt;/strong&gt;HH:MM:SS.SSS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ¹ ²&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ²&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;HH:MM&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;HH:MM:SS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;HH:MM:SS.SSS&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ² / Write&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;Timestamps since unix epoch&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read ³&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;&lt;code&gt;now&lt;/code&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;¹ Missing components are assumed to be zero. Dates are stored and read in the UTC time zone, unless the format is followed by a timezone indicator ⁽²⁾.&lt;/p&gt; 
&lt;p&gt;² This format may be optionally followed by a timezone indicator of the form &lt;code&gt;[+-]HH:MM&lt;/code&gt; or just &lt;code&gt;Z&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;³ GRDB 2+ interprets numerical values as timestamps that fuel &lt;code&gt;Date(timeIntervalSince1970:)&lt;/code&gt;. Previous GRDB versions used to interpret numbers as &lt;a href=&quot;https://en.wikipedia.org/wiki/Julian_day&quot;&gt;julian days&lt;/a&gt;. Julian days are still supported, with the &lt;code&gt;Date(julianDay:)&lt;/code&gt; initializer.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: the range of valid years in the SQLite date formats is 0000-9999. You will need to pick another date format when your application needs to process years outside of this range. See the following chapters.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h4&gt;Date&lt;/h4&gt; 
&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt; can be stored and fetched from the database just like other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try db.execute(
    sql: &quot;INSERT INTO player (creationDate, ...) VALUES (?, ...)&quot;,
    arguments: [Date(), ...])

let row = try Row.fetchOne(db, ...)!
let creationDate: Date = row[&quot;creationDate&quot;]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Dates are stored using the format &quot;YYYY-MM-DD HH:MM:SS.SSS&quot; in the UTC time zone. It is precise to the millisecond.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this format was chosen because it is the only format that is:&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;Comparable (&lt;code&gt;ORDER BY date&lt;/code&gt; works)&lt;/li&gt; 
  &lt;li&gt;Comparable with the SQLite keyword CURRENT_TIMESTAMP (&lt;code&gt;WHERE date &amp;gt; CURRENT_TIMESTAMP&lt;/code&gt; works)&lt;/li&gt; 
  &lt;li&gt;Able to feed &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;SQLite date &amp;amp; time functions&lt;/a&gt;&lt;/li&gt; 
  &lt;li&gt;Precise enough&lt;/li&gt; 
 &lt;/ul&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: the range of valid years in the SQLite date format is 0000-9999. You will experience problems with years outside of this range, such as decoding errors, or invalid date computations with &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;SQLite date &amp;amp; time functions&lt;/a&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;Some applications may prefer another date format:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Some may prefer ISO-8601, with a &lt;code&gt;T&lt;/code&gt; separator.&lt;/li&gt; 
 &lt;li&gt;Some may prefer ISO-8601, with a time zone.&lt;/li&gt; 
 &lt;li&gt;Some may need to store years beyond the 0000-9999 range.&lt;/li&gt; 
 &lt;li&gt;Some may need sub-millisecond precision.&lt;/li&gt; 
 &lt;li&gt;Some may need exact &lt;code&gt;Date&lt;/code&gt; roundtrip.&lt;/li&gt; 
 &lt;li&gt;Etc.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;You should think twice before choosing a different date format:&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;ISO-8601 is about &lt;em&gt;exchange and communication&lt;/em&gt;, when SQLite is about &lt;em&gt;storage and data manipulation&lt;/em&gt;. Sharing the same representation in your database and in JSON files only provides a superficial convenience, and should be the least of your priorities. Don&#39;t store dates as ISO-8601 without understanding what you lose. For example, ISO-8601 time zones forbid database-level date comparison.&lt;/li&gt; 
 &lt;li&gt;Sub-millisecond precision and exact &lt;code&gt;Date&lt;/code&gt; roundtrip are not as obvious needs as it seems at first sight. Dates generally don&#39;t precisely roundtrip as soon as they leave your application anyway, because the other systems your app communicates with use their own date representation (the Android version of your app, the server your application is talking to, etc.) On top of that, &lt;code&gt;Date&lt;/code&gt; comparison is at least as hard and nasty as &lt;a href=&quot;https://www.google.com/search?q=floating+point+comparison+is+hard&quot;&gt;floating point comparison&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;The customization of date format is explicit. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let date = Date()
let timeInterval = date.timeIntervalSinceReferenceDate
try db.execute(
    sql: &quot;INSERT INTO player (creationDate, ...) VALUES (?, ...)&quot;,
    arguments: [timeInterval, ...])

if let row = try Row.fetchOne(db, ...) {
    let timeInterval: TimeInterval = row[&quot;creationDate&quot;]
    let creationDate = Date(timeIntervalSinceReferenceDate: timeInterval)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See also &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more date customization options, and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt; if you want to define a Date-wrapping type with customized database representation.&lt;/p&gt; 
&lt;h4&gt;DateComponents&lt;/h4&gt; 
&lt;p&gt;DateComponents is indirectly supported, through the &lt;strong&gt;DatabaseDateComponents&lt;/strong&gt; helper type.&lt;/p&gt; 
&lt;p&gt;DatabaseDateComponents reads date components from all &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;date formats supported by SQLite&lt;/a&gt;, and stores them in the format of your choice, from HH:MM to YYYY-MM-DD HH:MM:SS.SSS.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: the range of valid years is 0000-9999. You will experience problems with years outside of this range, such as decoding errors, or invalid date computations with &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;SQLite date &amp;amp; time functions&lt;/a&gt;. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date&quot;&gt;Date&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;DatabaseDateComponents can be stored and fetched from the database just like other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let components = DateComponents()
components.year = 1973
components.month = 9
components.day = 18

// Store &quot;1973-09-18&quot;
let dbComponents = DatabaseDateComponents(components, format: .YMD)
try db.execute(
    sql: &quot;INSERT INTO player (birthDate, ...) VALUES (?, ...)&quot;,
    arguments: [dbComponents, ...])

// Read &quot;1973-09-18&quot;
let row = try Row.fetchOne(db, sql: &quot;SELECT birthDate ...&quot;)!
let dbComponents: DatabaseDateComponents = row[&quot;birthDate&quot;]
dbComponents.format         // .YMD (the actual format found in the database)
dbComponents.dateComponents // DateComponents
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;NSNumber, NSDecimalNumber, and Decimal&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;NSNumber&lt;/strong&gt; and &lt;strong&gt;Decimal&lt;/strong&gt; can be stored and fetched from the database just like other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Here is how GRDB supports the various data types supported by SQLite:&lt;/p&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;Integer&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;Double&lt;/th&gt; 
   &lt;th style=&quot;text-align:center&quot;&gt;String&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;NSNumber&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;NSDecimalNumber&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td style=&quot;text-align:left&quot;&gt;Decimal&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read&lt;/td&gt; 
   &lt;td style=&quot;text-align:center&quot;&gt;Read / Write&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;All three types can decode database integers and doubles:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let number = try NSNumber.fetchOne(db, sql: &quot;SELECT 10&quot;)            // NSNumber
let number = try NSDecimalNumber.fetchOne(db, sql: &quot;SELECT 1.23&quot;)   // NSDecimalNumber
let number = try Decimal.fetchOne(db, sql: &quot;SELECT -100&quot;)           // Decimal
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;All three types decode database strings as decimal numbers:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let number = try NSNumber.fetchOne(db, sql: &quot;SELECT &#39;10&#39;&quot;)          // NSDecimalNumber (sic)
let number = try NSDecimalNumber.fetchOne(db, sql: &quot;SELECT &#39;1.23&#39;&quot;) // NSDecimalNumber
let number = try Decimal.fetchOne(db, sql: &quot;SELECT &#39;-100&#39;&quot;)         // Decimal
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;NSNumber&lt;/code&gt; and &lt;code&gt;NSDecimalNumber&lt;/code&gt; send 64-bit signed integers and doubles in the database:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// INSERT INTO transfer VALUES (10)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [NSNumber(value: 10)])

// INSERT INTO transfer VALUES (10.0)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [NSNumber(value: 10.0)])

// INSERT INTO transfer VALUES (10)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [NSDecimalNumber(string: &quot;10.0&quot;)])

// INSERT INTO transfer VALUES (10.5)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [NSDecimalNumber(string: &quot;10.5&quot;)])
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: since SQLite does not support decimal numbers, sending a non-integer &lt;code&gt;NSDecimalNumber&lt;/code&gt; can result in a loss of precision during the conversion to double.&lt;/p&gt; 
   &lt;p&gt;Instead of sending non-integer &lt;code&gt;NSDecimalNumber&lt;/code&gt; to the database, you may prefer:&lt;/p&gt; 
   &lt;ul&gt; 
    &lt;li&gt;Send &lt;code&gt;Decimal&lt;/code&gt; instead (those store decimal strings in the database).&lt;/li&gt; 
    &lt;li&gt;Send integers instead (for example, store amounts of cents instead of amounts of Euros).&lt;/li&gt; 
   &lt;/ul&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;Decimal&lt;/code&gt; sends decimal strings in the database:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// INSERT INTO transfer VALUES (&#39;10&#39;)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [Decimal(10)])

// INSERT INTO transfer VALUES (&#39;10.5&#39;)
try db.execute(sql: &quot;INSERT INTO transfer VALUES (?)&quot;, arguments: [Decimal(string: &quot;10.5&quot;)!])
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;UUID&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;UUID&lt;/strong&gt; can be stored and fetched from the database just like other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;GRDB stores uuids as 16-bytes data blobs, and decodes them from both 16-bytes data blobs and strings such as &quot;E621E1F8-C36C-495A-93FC-0C247A3E6E5F&quot;.&lt;/p&gt; 
&lt;h3&gt;Swift Enums&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Swift enums&lt;/strong&gt; and generally all types that adopt the &lt;a href=&quot;https://developer.apple.com/library/tvos/documentation/Swift/Reference/Swift_RawRepresentable_Protocol/index.html&quot;&gt;RawRepresentable&lt;/a&gt; protocol can be stored and fetched from the database just like their raw &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;enum Color : Int {
    case red, white, rose
}

enum Grape : String {
    case chardonnay, merlot, riesling
}

// Declare empty DatabaseValueConvertible adoption
extension Color : DatabaseValueConvertible { }
extension Grape : DatabaseValueConvertible { }

// Store
try db.execute(
    sql: &quot;INSERT INTO wine (grape, color) VALUES (?, ?)&quot;,
    arguments: [Grape.merlot, Color.red])

// Read
let rows = try Row.fetchCursor(db, sql: &quot;SELECT * FROM wine&quot;)
while let row = try rows.next() {
    let grape: Grape = row[&quot;grape&quot;]
    let color: Color = row[&quot;color&quot;]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;When a database value does not match any enum case&lt;/strong&gt;, you get a fatal error. This fatal error can be avoided with the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; type:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT &#39;syrah&#39;&quot;)!

row[0] as String  // &quot;syrah&quot;
row[0] as Grape?  // fatal error: could not convert &quot;syrah&quot; to Grape.
row[0] as Grape   // fatal error: could not convert &quot;syrah&quot; to Grape.

let dbValue: DatabaseValue = row[0]
if dbValue.isNull {
    // Handle NULL
} else if let grape = Grape.fromDatabaseValue(dbValue) {
    // Handle valid grape
} else {
    // Handle unknown grape
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Custom SQL Functions and Aggregates&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;SQLite lets you define SQL functions and aggregates.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;A custom SQL function or aggregate extends SQLite:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT reverse(name) FROM player;   -- custom function
SELECT maxLength(name) FROM player; -- custom aggregate
&lt;/code&gt;&lt;/pre&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-sql-functions&quot;&gt;Custom SQL Functions&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-aggregates&quot;&gt;Custom Aggregates&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Custom SQL Functions&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasefunction&quot;&gt;&lt;code&gt;DatabaseFunction&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;A &lt;em&gt;function&lt;/em&gt; argument takes an array of &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt;, and returns any valid &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;value&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.) The number of database values is guaranteed to be &lt;em&gt;argumentCount&lt;/em&gt;.&lt;/p&gt; 
&lt;p&gt;SQLite has the opportunity to perform additional optimizations when functions are &quot;pure&quot;, which means that their result only depends on their arguments. So make sure to set the &lt;em&gt;pure&lt;/em&gt; argument to true when possible.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let reverse = DatabaseFunction(&quot;reverse&quot;, argumentCount: 1, pure: true) { (values: [DatabaseValue]) in
    // Extract string value, if any...
    guard let string = String.fromDatabaseValue(values[0]) else {
        return nil
    }
    // ... and return reversed string:
    return String(string.reversed())
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You make a function available to a database connection through its configuration:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    db.add(function: reverse)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)

try dbQueue.read { db in
    // &quot;oof&quot;
    try String.fetchOne(db, sql: &quot;SELECT reverse(&#39;foo&#39;)&quot;)!
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Functions can take a variable number of arguments:&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;When you don&#39;t provide any explicit &lt;em&gt;argumentCount&lt;/em&gt;, the function can take any number of arguments:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let averageOf = DatabaseFunction(&quot;averageOf&quot;, pure: true) { (values: [DatabaseValue]) in
    let doubles = values.compactMap { Double.fromDatabaseValue($0) }
    return doubles.reduce(0, +) / Double(doubles.count)
}
db.add(function: averageOf)

// 2.0
try Double.fetchOne(db, sql: &quot;SELECT averageOf(1, 2, 3)&quot;)!
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Functions can throw:&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let sqrt = DatabaseFunction(&quot;sqrt&quot;, argumentCount: 1, pure: true) { (values: [DatabaseValue]) in
    guard let double = Double.fromDatabaseValue(values[0]) else {
        return nil
    }
    guard double &amp;gt;= 0 else {
        throw DatabaseError(message: &quot;invalid negative number&quot;)
    }
    return sqrt(double)
}
db.add(function: sqrt)

// SQLite error 1 with statement `SELECT sqrt(-1)`: invalid negative number
try Double.fetchOne(db, sql: &quot;SELECT sqrt(-1)&quot;)!
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Use custom functions in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;:&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT reverseString(&quot;name&quot;) FROM player
Player.select { reverseString($0.name) }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;GRDB ships with built-in SQL functions that perform unicode-aware string transformations.&lt;/strong&gt; See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#unicode&quot;&gt;Unicode&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;Custom Aggregates&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasefunction&quot;&gt;&lt;code&gt;DatabaseFunction&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseaggregate&quot;&gt;&lt;code&gt;DatabaseAggregate&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;Before registering a custom aggregate, you need to define a type that adopts the &lt;code&gt;DatabaseAggregate&lt;/code&gt; protocol:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol DatabaseAggregate {
    // Initializes an aggregate
    init()
    
    // Called at each step of the aggregation
    mutating func step(_ dbValues: [DatabaseValue]) throws
    
    // Returns the final result
    func finalize() throws -&amp;gt; DatabaseValueConvertible?
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct MaxLength : DatabaseAggregate {
    var maxLength: Int = 0
    
    mutating func step(_ dbValues: [DatabaseValue]) {
        // At each step, extract string value, if any...
        guard let string = String.fromDatabaseValue(dbValues[0]) else {
            return
        }
        // ... and update the result
        let length = string.count
        if length &amp;gt; maxLength {
            maxLength = length
        }
    }
    
    func finalize() -&amp;gt; DatabaseValueConvertible? {
        maxLength
    }
}

let maxLength = DatabaseFunction(
    &quot;maxLength&quot;,
    argumentCount: 1,
    pure: true,
    aggregate: MaxLength.self)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Like &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-sql-functions&quot;&gt;custom SQL Functions&lt;/a&gt;, you make an aggregate function available to a database connection through its configuration:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    db.add(function: maxLength)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)

try dbQueue.read { db in
    // Some Int
    try Int.fetchOne(db, sql: &quot;SELECT maxLength(name) FROM player&quot;)!
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;step&lt;/code&gt; method of the aggregate takes an array of &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt;. This array contains as many values as the &lt;em&gt;argumentCount&lt;/em&gt; parameter (or any number of values, when &lt;em&gt;argumentCount&lt;/em&gt; is omitted).&lt;/p&gt; 
&lt;p&gt;The &lt;code&gt;finalize&lt;/code&gt; method of the aggregate returns the final aggregated &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;value&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.).&lt;/p&gt; 
&lt;p&gt;SQLite has the opportunity to perform additional optimizations when aggregates are &quot;pure&quot;, which means that their result only depends on their inputs. So make sure to set the &lt;em&gt;pure&lt;/em&gt; argument to true when possible.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Use custom aggregates in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;:&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT maxLength(&quot;name&quot;) FROM player
let request = Player.select { maxLength($0.name) }
try Int.fetchOne(db, request) // Int?
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Raw SQLite Pointers&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;If not all SQLite APIs are exposed in GRDB, you can still use the &lt;a href=&quot;https://www.sqlite.org/c3ref/intro.html&quot;&gt;SQLite C Interface&lt;/a&gt; and call &lt;a href=&quot;https://www.sqlite.org/c3ref/funclist.html&quot;&gt;SQLite C functions&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;To access the C SQLite functions from SQLCipher or the system SQLite, you need to perform an extra import:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import SQLite3   // System SQLite
import SQLCipher // SQLCipher

let sqliteVersion = String(cString: sqlite3_libversion())
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Raw pointers to database connections and statements are available through the &lt;code&gt;Database.sqliteConnection&lt;/code&gt; and &lt;code&gt;Statement.sqliteStatement&lt;/code&gt; properties:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    // The raw pointer to a database connection:
    let sqliteConnection = db.sqliteConnection

    // The raw pointer to a statement:
    let statement = try db.makeStatement(sql: &quot;SELECT ...&quot;)
    let sqliteStatement = statement.sqliteStatement
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;Those pointers are owned by GRDB: don&#39;t close connections or finalize statements created by GRDB.&lt;/li&gt; 
  &lt;li&gt;GRDB opens SQLite connections in the &quot;&lt;a href=&quot;https://www.sqlite.org/threadsafe.html&quot;&gt;multi-thread mode&lt;/a&gt;&quot;, which (oddly) means that &lt;strong&gt;they are not thread-safe&lt;/strong&gt;. Make sure you touch raw databases and statements inside their dedicated dispatch queues.&lt;/li&gt; 
  &lt;li&gt;Use the raw SQLite C Interface at your own risk. GRDB won&#39;t prevent you from shooting yourself in the foot.&lt;/li&gt; 
 &lt;/ul&gt; 
&lt;/blockquote&gt; 
&lt;h1&gt;Records&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;On top of the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-api&quot;&gt;SQLite API&lt;/a&gt;, GRDB provides protocols&lt;/strong&gt; that help manipulating database rows as regular objects named &quot;records&quot;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    if var player = try Player.fetchOne(db, id: 1) {
        player.score += 10
        try player.update(db)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Of course, you need to open a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;database connection&lt;/a&gt;, and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseschema&quot;&gt;create database tables&lt;/a&gt; first.&lt;/p&gt; 
&lt;p&gt;To define a record type, define a type and extend it with database protocols:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;FetchableRecord&lt;/code&gt; makes it possible to fetch instances from the database.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;PersistableRecord&lt;/code&gt; makes it possible to save instances into the database.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Codable&lt;/code&gt; (not mandatory) provides ready-made serialization to and from database rows.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Identifiable&lt;/code&gt; (not mandatory) provides extra convenience database methods.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;To make it easier to customize database requests, also nest a &lt;code&gt;Columns&lt;/code&gt; enum:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Codable, Identifiable {
    var id: Int64
    var name: String
    var score: Int
    var team: String?
}

// Add database support
extension Player: FetchableRecord, PersistableRecord {
    enum Columns {
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
        static let team = Column(CodingKeys.team)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See more &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#examples-of-record-definitions&quot;&gt;examples of record definitions&lt;/a&gt; below.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;Note: if you are familiar with Core Data&#39;s NSManagedObject or Realm&#39;s Object, you may experience a cultural shock: GRDB records are not uniqued, do not auto-update, and do not lazy-load. This is both a purpose, and a consequence of protocol-oriented programming.&lt;/p&gt; 
 &lt;p&gt;Tip: The &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recordrecommendedpractices&quot;&gt;Recommended Practices for Designing Record Types&lt;/a&gt; guide provides general guidance..&lt;/p&gt; 
 &lt;p&gt;Tip: See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/DemoApps&quot;&gt;Demo Applications&lt;/a&gt; for sample apps that uses records.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#inserting-records&quot;&gt;Inserting Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-records&quot;&gt;Fetching Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#updating-records&quot;&gt;Updating Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#deleting-records&quot;&gt;Deleting Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#counting-records&quot;&gt;Counting Records&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Protocols and the Record Class&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;Record Protocols Overview&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord Protocol&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord Protocol&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord Protocol&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-methods&quot;&gt;Persistence Methods&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-methods-and-the-returning-clause&quot;&gt;Persistence Methods and the &lt;code&gt;RETURNING&lt;/code&gt; clause&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;Persistence Callbacks&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;Record Comparison&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-customization-options&quot;&gt;Record Customization Options&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recordtimestamps&quot;&gt;Record Timestamps and Transaction Date&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Inserting Records&lt;/h3&gt; 
&lt;p&gt;To insert a record in the database, call the &lt;code&gt;insert&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let player = Player(id: 1, name: &quot;Arthur&quot;, score: 1000)
try player.insert(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;👉 &lt;code&gt;insert&lt;/code&gt; is available for types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;h3&gt;Fetching Records&lt;/h3&gt; 
&lt;p&gt;To fetch records from the database, call a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;fetching method&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let arthur = try Player.fetchOne(db,            // Player?
    sql: &quot;SELECT * FROM players WHERE name = ?&quot;,
    arguments: [&quot;Arthur&quot;])

let bestPlayers = try Player                    // [Player]
    .order(\.score.desc)
    .limit(10)
    .fetchAll(db)
    
let spain = try Country.fetchOne(db, id: &quot;ES&quot;)  // Country?
let italy = try Country.find(db, id: &quot;IT&quot;)      // Country
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;👉 Fetching from raw SQL is available for types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;p&gt;👉 Fetching without SQL, using the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;, is available for types that adopt both &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;h3&gt;Updating Records&lt;/h3&gt; 
&lt;p&gt;To update a record in the database, call the &lt;code&gt;update&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var player: Player = ...
player.score = 1000
try player.update(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;It is possible to &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;avoid useless updates&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// does not hit the database if score has not changed
try player.updateChanges(db) {
    $0.score = 1000
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt; for batch updates:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player
    .filter { $0.team == &quot;red&quot; }
    .updateAll(db) { $0.score += 1 }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;👉 update methods are available for types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; protocol. Batch updates are available on the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;h3&gt;Deleting Records&lt;/h3&gt; 
&lt;p&gt;To delete a record in the database, call the &lt;code&gt;delete&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let player: Player = ...
try player.delete(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also delete by primary key, unique key, or perform batch deletes (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#delete-requests&quot;&gt;Delete Requests&lt;/a&gt;):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.deleteOne(db, id: 1)
try Player.deleteOne(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
try Country.deleteAll(db, ids: [&quot;FR&quot;, &quot;US&quot;])
try Player
    .filter { $0.email == nil }
    .deleteAll(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;👉 delete methods are available for types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; protocol. Batch deletes are available on the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;h3&gt;Counting Records&lt;/h3&gt; 
&lt;p&gt;To count records, call the &lt;code&gt;fetchCount&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let playerCount: Int = try Player.fetchCount(db)

let playerWithEmailCount: Int = try Player
    .filter { $0.email == nil }
    .fetchCount(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;👉 &lt;code&gt;fetchCount&lt;/code&gt; is available for types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;p&gt;Details follow:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;Record Protocols Overview&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord Protocol&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord Protocol&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord Protocol&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;Record Comparison&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-customization-options&quot;&gt;Record Customization Options&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#examples-of-record-definitions&quot;&gt;Examples of Record Definitions&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Record Protocols Overview&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;GRDB ships with three record protocols&lt;/strong&gt;. Your own types will adopt one or several of them, according to the abilities you want to extend your types with.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; is able to &lt;strong&gt;decode database rows&lt;/strong&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: FetchableRecord { ... }

let places = try dbQueue.read { db in
    try Place.fetchAll(db, sql: &quot;SELECT * FROM place&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;: &lt;code&gt;FetchableRecord&lt;/code&gt; can derive its implementation from the standard &lt;code&gt;Decodable&lt;/code&gt; protocol. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more information.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;p&gt;&lt;code&gt;FetchableRecord&lt;/code&gt; can decode database rows, but it is not able to build SQL requests for you. For that, you also need &lt;code&gt;TableRecord&lt;/code&gt;:&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; is able to &lt;strong&gt;generate SQL queries&lt;/strong&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: TableRecord { ... }

let placeCount = try dbQueue.read { db in
    // Generates and runs `SELECT COUNT(*) FROM place`
    try Place.fetchCount(db)
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When a type adopts both &lt;code&gt;TableRecord&lt;/code&gt; and &lt;code&gt;FetchableRecord&lt;/code&gt;, it can load from those requests:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: TableRecord, FetchableRecord { ... }

try dbQueue.read { db in
    let places = try Place.order(\.title).fetchAll(db)
    let paris = try Place.fetchOne(id: 1)
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; is able to &lt;strong&gt;write&lt;/strong&gt;: it can create, update, and delete rows in the database:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place : PersistableRecord { ... }

try dbQueue.write { db in
    try Place.delete(db, id: 1)
    try Place(...).insert(db)
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;A persistable record can also &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;compare&lt;/a&gt; itself against other records, and avoid useless database updates.&lt;/p&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;: &lt;code&gt;PersistableRecord&lt;/code&gt; can derive its implementation from the standard &lt;code&gt;Encodable&lt;/code&gt; protocol. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more information.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;FetchableRecord Protocol&lt;/h2&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/fetchablerecord&quot;&gt;&lt;code&gt;FetchableRecord&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;The FetchableRecord protocol grants fetching methods to any type&lt;/strong&gt; that can be built from a database row:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol FetchableRecord {
    /// Row initializer
    init(row: Row) throws
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place {
    var id: Int64?
    var title: String
    var coordinate: CLLocationCoordinate2D
}

extension Place: FetchableRecord {
    enum Columns {
        static let id = Column(&quot;id&quot;)
        static let title = Column(&quot;title&quot;)
        static let latitude = Column(&quot;latitude&quot;)
        static let longitude = Column(&quot;longitude&quot;)
    }
    
    init(row: Row) {
        id = row[Columns.id]
        title = row[Columns.title]
        coordinate = CLLocationCoordinate2D(
            latitude: row[Columns.latitude],
            longitude: row[Columns.longitude])
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#column-values&quot;&gt;column values&lt;/a&gt; for more information about the &lt;code&gt;row[]&lt;/code&gt; subscript.&lt;/p&gt; 
&lt;p&gt;When your record type adopts the standard Decodable protocol, you don&#39;t have to provide the implementation for &lt;code&gt;init(row:)&lt;/code&gt;. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more information:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// That&#39;s all
struct Player: Decodable, FetchableRecord {
    var id: Int64
    var name: String
    var score: Int
    
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;FetchableRecord allows adopting types to be fetched from SQL queries:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Place.fetchCursor(db, sql: &quot;SELECT ...&quot;, arguments:...) // A Cursor of Place
try Place.fetchAll(db, sql: &quot;SELECT ...&quot;, arguments:...)    // [Place]
try Place.fetchSet(db, sql: &quot;SELECT ...&quot;, arguments:...)    // Set&amp;lt;Place&amp;gt;
try Place.fetchOne(db, sql: &quot;SELECT ...&quot;, arguments:...)    // Place?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;fetching methods&lt;/a&gt; for information about the &lt;code&gt;fetchCursor&lt;/code&gt;, &lt;code&gt;fetchAll&lt;/code&gt;, &lt;code&gt;fetchSet&lt;/code&gt; and &lt;code&gt;fetchOne&lt;/code&gt; methods. See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statementarguments&quot;&gt;&lt;code&gt;StatementArguments&lt;/code&gt;&lt;/a&gt; for more information about the query arguments.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: for performance reasons, the same row argument to &lt;code&gt;init(row:)&lt;/code&gt; is reused during the iteration of a fetch query. If you want to keep the row for later use, make sure to store a copy: &lt;code&gt;self.row = row.copy()&lt;/code&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The &lt;code&gt;FetchableRecord.init(row:)&lt;/code&gt; initializer fits the needs of most applications. But some application are more demanding than others. When FetchableRecord does not exactly provide the support you need, have a look at the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#beyond-fetchablerecord&quot;&gt;Beyond FetchableRecord&lt;/a&gt; chapter.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;TableRecord Protocol&lt;/h2&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerecord&quot;&gt;&lt;code&gt;TableRecord&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;The TableRecord protocol&lt;/strong&gt; generates SQL for you:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol TableRecord {
    static var databaseTableName: String { get }
    static var databaseSelection: [any SQLSelectable] { get }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;databaseSelection&lt;/code&gt; type property is optional, and documented in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#columns-selected-by-a-request&quot;&gt;Columns Selected by a Request&lt;/a&gt; chapter.&lt;/p&gt; 
&lt;p&gt;The &lt;code&gt;databaseTableName&lt;/code&gt; type property is the name of a database table. By default, it is derived from the type name:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: TableRecord { }

print(Place.databaseTableName) // prints &quot;place&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Place: &lt;code&gt;place&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Country: &lt;code&gt;country&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;PostalAddress: &lt;code&gt;postalAddress&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;HTTPRequest: &lt;code&gt;httpRequest&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;TOEFL: &lt;code&gt;toefl&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;You can still provide a custom table name:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: TableRecord {
    static let databaseTableName = &quot;location&quot;
}

print(Place.databaseTableName) // prints &quot;location&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When a type adopts both TableRecord and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt;, it can be fetched using the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM place WHERE name = &#39;Paris&#39;
let paris = try Place.filter { $0.name == &quot;Paris&quot; }.fetchOne(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;TableRecord can also fetch deal with primary and unique keys: see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-by-key&quot;&gt;Fetching by Key&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#testing-for-record-existence&quot;&gt;Testing for Record Existence&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;PersistableRecord Protocol&lt;/h2&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/encodablerecord&quot;&gt;&lt;code&gt;EncodableRecord&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/mutablepersistablerecord&quot;&gt;&lt;code&gt;MutablePersistableRecord&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/persistablerecord&quot;&gt;&lt;code&gt;PersistableRecord&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;GRDB record types can create, update, and delete rows in the database.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Those abilities are granted by three protocols:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Defines how a record encodes itself into the database
protocol EncodableRecord {
    /// Defines the values persisted in the database
    func encode(to container: inout PersistenceContainer) throws
}

// Adds persistence methods
protocol MutablePersistableRecord: TableRecord, EncodableRecord {
    /// Optional method that lets your adopting type store its rowID upon
    /// successful insertion. Don&#39;t call it directly: it is called for you.
    mutating func didInsert(_ inserted: InsertionSuccess)
}

// Adds immutability
protocol PersistableRecord: MutablePersistableRecord {
    /// Non-mutating version of the optional didInsert(_:)
    func didInsert(_ inserted: InsertionSuccess)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Yes, three protocols instead of one. Here is how you pick one or the other:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;If your type is a class&lt;/strong&gt;, choose &lt;code&gt;PersistableRecord&lt;/code&gt;. On top of that, implement &lt;code&gt;didInsert(_:)&lt;/code&gt; if the database table has an auto-incremented primary key.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;If your type is a struct, and the database table has an auto-incremented primary key&lt;/strong&gt;, choose &lt;code&gt;MutablePersistableRecord&lt;/code&gt;, and implement &lt;code&gt;didInsert(_:)&lt;/code&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Otherwise&lt;/strong&gt;, choose &lt;code&gt;PersistableRecord&lt;/code&gt;, and ignore &lt;code&gt;didInsert(_:)&lt;/code&gt;.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;The &lt;code&gt;encode(to:)&lt;/code&gt; method defines which &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.) are assigned to database columns.&lt;/p&gt; 
&lt;p&gt;The optional &lt;code&gt;didInsert&lt;/code&gt; method lets the adopting type store its rowID after successful insertion, and is only useful for tables that have an auto-incremented primary key. It is called from a protected dispatch queue, and serialized with all database updates.&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Place: MutablePersistableRecord {
    enum Columns {
        static let id = Column(&quot;id&quot;)
        static let title = Column(&quot;title&quot;)
        static let latitude = Column(&quot;latitude&quot;)
        static let longitude = Column(&quot;longitude&quot;)
    }
    
    /// The values persisted in the database
    func encode(to container: inout PersistenceContainer) {
        container[Columns.id] = id
        container[Columns.title] = title
        container[Columns.latitude] = coordinate.latitude
        container[Columns.longitude] = coordinate.longitude
    }
    
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}

var paris = Place(
    id: nil,
    title: &quot;Paris&quot;,
    coordinate: CLLocationCoordinate2D(latitude: 48.8534100, longitude: 2.3488000))

try paris.insert(db)
paris.id   // some value
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When your record type adopts the standard Encodable protocol, you don&#39;t have to provide the implementation for &lt;code&gt;encode(to:)&lt;/code&gt;. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more information:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// That&#39;s all
struct Player: Encodable, MutablePersistableRecord {
    var id: Int64?
    var name: String
    var score: Int
    
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
    
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Persistence Methods&lt;/h3&gt; 
&lt;p&gt;Types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; protocol are given methods that insert, update, and delete:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// INSERT
try place.insert(db)
let insertedPlace = try place.inserted(db) // non-mutating

// UPDATE
try place.update(db)
try place.update(db, columns: [&quot;title&quot;])

// Maybe UPDATE
try place.updateChanges(db, from: otherPlace)
try place.updateChanges(db) { $0.isFavorite = true }

// INSERT or UPDATE
try place.save(db)
let savedPlace = place.saved(db) // non-mutating

// UPSERT
try place.upsert(db)
let insertedPlace = place.upsertAndFetch(db)

// DELETE
try place.delete(db)

// EXISTENCE CHECK
let exists = try place.exists(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#upsert&quot;&gt;Upsert&lt;/a&gt; below for more information about upserts.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol comes with batch operations&lt;/strong&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// UPDATE
try Place.updateAll(db, ...)

// DELETE
try Place.deleteAll(db)
try Place.deleteAll(db, ids:...)
try Place.deleteAll(db, keys:...)
try Place.deleteOne(db, id:...)
try Place.deleteOne(db, key:...)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For more information about batch updates, see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#update-requests&quot;&gt;Update Requests&lt;/a&gt;.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;All persistence methods can throw a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#error-handling&quot;&gt;DatabaseError&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;update&lt;/code&gt; and &lt;code&gt;updateChanges&lt;/code&gt; throw &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#recorderror&quot;&gt;RecordError&lt;/a&gt; if the database does not contain any row for the primary key of the record.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;save&lt;/code&gt; makes sure your values are stored in the database. It performs an UPDATE if the record has a non-null primary key, and then, if no row was modified, an INSERT. It directly performs an INSERT if the record has no primary key, or a null primary key.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;delete&lt;/code&gt; and &lt;code&gt;deleteOne&lt;/code&gt; returns whether a database row was deleted or not. &lt;code&gt;deleteAll&lt;/code&gt; returns the number of deleted rows. &lt;code&gt;updateAll&lt;/code&gt; returns the number of updated rows. &lt;code&gt;updateChanges&lt;/code&gt; returns whether a database row was updated or not.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;All primary keys are supported&lt;/strong&gt;, including composite primary keys that span several columns, and the &lt;a href=&quot;https://www.sqlite.org/rowidtable.html&quot;&gt;hidden &lt;code&gt;rowid&lt;/code&gt; column&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;To customize persistence methods&lt;/strong&gt;, you provide &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;Persistence Callbacks&lt;/a&gt;, described below. Do not attempt at overriding the ready-made persistence methods.&lt;/p&gt; 
&lt;h3&gt;Upsert&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://www.sqlite.org/lang_UPSERT.html&quot;&gt;UPSERT&lt;/a&gt; is an SQLite feature that causes an INSERT to behave as an UPDATE or a no-op if the INSERT would violate a uniqueness constraint (primary key or unique index).&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Upsert apis are available from SQLite 3.35.0+: iOS 15.0+, macOS 12.0+, tvOS 15.0+, watchOS 8.0+, or with a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CustomSQLiteBuilds.md&quot;&gt;custom SQLite build&lt;/a&gt; or &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#encryption&quot;&gt;SQLCipher&lt;/a&gt;.&lt;/p&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: With regard to &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#available-callbacks&quot;&gt;persistence callbacks&lt;/a&gt;, an upsert behaves exactly like an insert. In particular: the &lt;code&gt;aroundInsert(_:)&lt;/code&gt; and &lt;code&gt;didInsert(_:)&lt;/code&gt; callbacks reports the rowid of the inserted or updated row; &lt;code&gt;willUpdate&lt;/code&gt;, &lt;code&gt;aroundUpdate&lt;/code&gt;, &lt;code&gt;didUpdate&lt;/code&gt; are not called.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; provides three upsert methods:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;upsert(_:)&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Inserts or updates a record.&lt;/p&gt; &lt;p&gt;The upsert behavior is triggered by a violation of any uniqueness constraint on the table (primary key or unique index). In case of conflict, all columns but the primary key are overwritten with the inserted values:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Encodable, PersistableRecord {
    var id: Int64
    var name: String
    var score: Int
}

// INSERT INTO player (id, name, score)
// VALUES (1, &#39;Arthur&#39;, 1000)
// ON CONFLICT DO UPDATE SET
//   name = excluded.name,
//   score = excluded.score
let player = Player(id: 1, name: &quot;Arthur&quot;, score: 1000)
try player.upsert(db)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;upsertAndFetch(_:onConflict:updating:doUpdate:)&lt;/code&gt; (requires &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; conformance)&lt;/p&gt; &lt;p&gt;Inserts or updates a record, and returns the upserted record.&lt;/p&gt; &lt;p&gt;The &lt;code&gt;onConflict&lt;/code&gt; and &lt;code&gt;doUpdate&lt;/code&gt; arguments let you further control the upsert behavior. Make sure you check the &lt;a href=&quot;https://www.sqlite.org/lang_UPSERT.html&quot;&gt;SQLite UPSERT documentation&lt;/a&gt; for detailed information.&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt; &lt;p&gt;&lt;code&gt;onConflict&lt;/code&gt;: the &quot;conflict target&quot; is the array of columns in the uniqueness constraint (primary key or unique index) that triggers the upsert.&lt;/p&gt; &lt;p&gt;If empty (the default), all uniqueness constraint are considered.&lt;/p&gt; &lt;/li&gt; 
   &lt;li&gt; &lt;p&gt;&lt;code&gt;doUpdate&lt;/code&gt;: a closure that returns columns assignments to perform in case of conflict. Depending on the &lt;code&gt;options&lt;/code&gt; parameter, other columns are overwritten with the inserted values, or not.&lt;/p&gt; &lt;p&gt;By default, all inserted columns but the primary key and the conflict target are overwritten.&lt;/p&gt; &lt;/li&gt; 
  &lt;/ul&gt; &lt;p&gt;In the example below, we upsert the new vocabulary word &quot;jovial&quot;. It is inserted if that word is not already in the dictionary. Otherwise, &lt;code&gt;count&lt;/code&gt; is incremented, &lt;code&gt;isTainted&lt;/code&gt; is not overwritten, and &lt;code&gt;kind&lt;/code&gt; is overwritten:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// CREATE TABLE vocabulary(
//   word TEXT NOT NULL PRIMARY KEY,
//   kind TEXT NOT NULL,
//   isTainted BOOLEAN DEFAULT 0,
//   count INT DEFAULT 1))
struct Vocabulary: Encodable, PersistableRecord {
    var word: String
    var kind: String
    var isTainted: Bool
}

// INSERT INTO vocabulary(word, kind, isTainted)
// VALUES(&#39;jovial&#39;, &#39;adjective&#39;, 0)
// ON CONFLICT(word) DO UPDATE SET \
//   count = count + 1,   -- on conflict, count is incremented
//   kind = excluded.kind -- on conflict, kind is overwritten
// RETURNING *
let vocabulary = Vocabulary(word: &quot;jovial&quot;, kind: &quot;adjective&quot;, isTainted: false)
let upserted = try vocabulary.upsertAndFetch(
    db, onConflict: [&quot;word&quot;],
    doUpdate: { _ in
        [Column(&quot;count&quot;) += 1,            // on conflict, count is incremented
         Column(&quot;isTainted&quot;).noOverwrite] // on conflict, isTainted is NOT overwritten
    })
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The &lt;code&gt;doUpdate&lt;/code&gt; closure accepts an &lt;code&gt;excluded&lt;/code&gt; TableAlias argument that refers to the inserted values that trigger the conflict. You can use it to specify an explicit overwrite, or to perform a computation. In the next example, the upsert keeps the maximum date in case of conflict:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// INSERT INTO message(id, text, date)
// VALUES(...)
// ON CONFLICT DO UPDATE SET \
//   text = excluded.text,
//   date = MAX(date, excluded.date)
// RETURNING *
let upserted = try message.upsertAndFetch(doUpdate: { excluded in
    // keep the maximum date in case of conflict
    [Column(&quot;date&quot;).set(to: max(Column(&quot;date&quot;), excluded[&quot;date&quot;]))]
})
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;upsertAndFetch(_:as:onConflict:updating:doUpdate:)&lt;/code&gt; (does not require &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; conformance)&lt;/p&gt; &lt;p&gt;This method is identical to &lt;code&gt;upsertAndFetch(_:onConflict:updating:doUpdate:)&lt;/code&gt; described above, but you can provide a distinct &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; record type as a result, in order to specify the returned columns.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Persistence Methods and the &lt;code&gt;RETURNING&lt;/code&gt; clause&lt;/h3&gt; 
&lt;p&gt;SQLite is able to return values from a inserted, updated, or deleted row, with the &lt;a href=&quot;https://www.sqlite.org/lang_returning.html&quot;&gt;&lt;code&gt;RETURNING&lt;/code&gt; clause&lt;/a&gt;.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Support for the &lt;code&gt;RETURNING&lt;/code&gt; clause is available from SQLite 3.35.0+: iOS 15.0+, macOS 12.0+, tvOS 15.0+, watchOS 8.0+, or with a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CustomSQLiteBuilds.md&quot;&gt;custom SQLite build&lt;/a&gt; or &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#encryption&quot;&gt;SQLCipher&lt;/a&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;The &lt;code&gt;RETURNING&lt;/code&gt; clause helps dealing with database features such as auto-incremented ids, default values, and &lt;a href=&quot;https://sqlite.org/gencol.html&quot;&gt;generated columns&lt;/a&gt;. You can, for example, insert a few columns and fetch the default or generated ones in one step.&lt;/p&gt; 
&lt;p&gt;GRDB uses the &lt;code&gt;RETURNING&lt;/code&gt; clause in all persistence methods that contain &lt;code&gt;AndFetch&lt;/code&gt; in their name.&lt;/p&gt; 
&lt;p&gt;For example, given a database table with an auto-incremented primary key and a default score:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try db.execute(sql: &quot;&quot;&quot;
        CREATE TABLE player(
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          name TEXT NOT NULL,
          score INTEGER NOT NULL DEFAULT 1000)
        &quot;&quot;&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can define a record type with full database information, and another partial record type that deals with a subset of columns:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// A player with full database information
struct Player: Codable, PersistableRecord, FetchableRecord {
    var id: Int64
    var name: String
    var score: Int
    
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}

// A partial player
struct PartialPlayer: Encodable, PersistableRecord {
    static let databaseTableName = &quot;player&quot;
    var name: String
    
    typealias Columns = Player.Columns
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;And now you can get a full player by inserting a partial one:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    let partialPlayer = PartialPlayer(name: &quot;Alice&quot;)
    
    // INSERT INTO player (name) VALUES (&#39;Alice&#39;) RETURNING *
    let player = try partialPlayer.insertAndFetch(db, as: Player.self)
    print(player.id)    // The inserted id
    print(player.name)  // The inserted name
    print(player.score) // The default score
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For extra precision, you can select only the columns you need, and fetch the desired value from the provided prepared &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;&lt;code&gt;Statement&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    let partialPlayer = PartialPlayer(name: &quot;Alice&quot;)
    
    // INSERT INTO player (name) VALUES (&#39;Alice&#39;) RETURNING score
    let score = try partialPlayer.insertAndFetch(db) { statement in
        try Int.fetchOne(statement)
    } select: {
        [$0.score]
    }
    print(score) // Prints 1000, the default score
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;There are other similar persistence methods, such as &lt;code&gt;upsertAndFetch&lt;/code&gt;, &lt;code&gt;saveAndFetch&lt;/code&gt;, &lt;code&gt;updateAndFetch&lt;/code&gt;, &lt;code&gt;updateChangesAndFetch&lt;/code&gt;, etc. They all behave like &lt;code&gt;upsert&lt;/code&gt;, &lt;code&gt;save&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;updateChanges&lt;/code&gt;, except that they return saved values. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Save and return the saved player
let savedPlayer = try player.saveAndFetch(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-methods&quot;&gt;Persistence Methods&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#upsert&quot;&gt;Upsert&lt;/a&gt;, and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-updatechanges-methods&quot;&gt;&lt;code&gt;updateChanges&lt;/code&gt; methods&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Batch operations&lt;/strong&gt; can return updated or deleted values:&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Make sure you check the &lt;a href=&quot;https://www.sqlite.org/lang_returning.html#limitations_and_caveats&quot;&gt;documentation of the &lt;code&gt;RETURNING&lt;/code&gt; clause&lt;/a&gt;, which describes important limitations and caveats for batch operations.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.filter(...)...

// Fetch all deleted players
// DELETE FROM player RETURNING *
let deletedPlayers = try request.deleteAndFetchAll(db) // [Player]

// Fetch a selection of columns from the deleted rows
// DELETE FROM player RETURNING name
let statement = try request.deleteAndFetchStatement(db) { [$0.name] }
let deletedNames = try String.fetchSet(statement)

// Fetch all updated players
// UPDATE player SET score = score + 10 RETURNING *
let updatedPlayers = try request.updateAndFetchAll(db) { [$0.score += 10] } // [Player]

// Fetch a selection of columns from the updated rows
// UPDATE player SET score = score + 10 RETURNING score
let statement = try request.updateAndFetchStatement(db) {
    [$0.score += 10]
} select: {
    [$0.score]
}
let updatedScores = try Int.fetchAll(statement)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Persistence Callbacks&lt;/h3&gt; 
&lt;p&gt;Your custom type may want to perform extra work when the persistence methods are invoked.&lt;/p&gt; 
&lt;p&gt;To this end, your record type can implement &lt;strong&gt;persistence callbacks&lt;/strong&gt;. Callbacks are methods that get called at certain moments of a record&#39;s life cycle. With callbacks it is possible to write code that will run whenever an record is inserted, updated, or deleted.&lt;/p&gt; 
&lt;p&gt;In order to use a callback method, you need to provide its implementation. For example, a frequently used callback is &lt;code&gt;didInsert&lt;/code&gt;, in the case of auto-incremented database ids:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: MutablePersistableRecord {
    var id: Int64?
    
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}

try dbQueue.write { db in
    var player = Player(id: nil, ...)
    try player.insert(db)
    print(player.id) // didInsert was called: prints some non-nil id
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Callbacks can also help implementing record validation:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Link: PersistableRecord {
    var url: URL
    
    func willSave(_ db: Database) throws {
        if url.host == nil {
            throw ValidationError(&quot;url must be absolute.&quot;)
        }
    }
}

try link.insert(db) // Calls the willSave callback
try link.update(db) // Calls the willSave callback
try link.save(db)   // Calls the willSave callback
try link.upsert(db) // Calls the willSave callback
&lt;/code&gt;&lt;/pre&gt; 
&lt;h4&gt;Available Callbacks&lt;/h4&gt; 
&lt;p&gt;Here is a list with all the available &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;persistence callbacks&lt;/a&gt;, listed in the same order in which they will get called during the respective operations:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;Inserting a record (all &lt;code&gt;record.insert&lt;/code&gt; and &lt;code&gt;record.upsert&lt;/code&gt; methods)&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;code&gt;willSave&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;aroundSave&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;willInsert&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;aroundInsert&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;didInsert&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;didSave&lt;/code&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Updating a record (all &lt;code&gt;record.update&lt;/code&gt; methods)&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;code&gt;willSave&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;aroundSave&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;willUpdate&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;aroundUpdate&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;didUpdate&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;didSave&lt;/code&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Deleting a record (only the &lt;code&gt;record.delete(_:)&lt;/code&gt; method)&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;code&gt;willDelete&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;aroundDelete&lt;/code&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;code&gt;didDelete&lt;/code&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;For detailed information about each callback, check the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/mutablepersistablerecord/&quot;&gt;reference&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;In the &lt;code&gt;MutablePersistableRecord&lt;/code&gt; protocol, &lt;code&gt;willInsert&lt;/code&gt; and &lt;code&gt;didInsert&lt;/code&gt; are mutating methods. In &lt;code&gt;PersistableRecord&lt;/code&gt;, they are not mutating.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The &lt;code&gt;record.save(_:)&lt;/code&gt; method performs an UPDATE if the record has a non-null primary key, and then, if no row was modified, an INSERT. It directly performs an INSERT if the record has no primary key, or a null primary key. It triggers update and/or insert callbacks accordingly.&lt;/p&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Callbacks are only invoked from persistence methods called on record instances. Callbacks are not invoked when you call a type method, perform a batch operations, or execute raw SQL.&lt;/p&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: When a &lt;code&gt;did***&lt;/code&gt; callback is invoked, do not assume that the change is actually persisted on disk, because the database may still be inside an uncommitted transaction. When you need to handle transaction completions, use the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/afternexttransaction(oncommit:onrollback:)&quot;&gt;afterNextTransaction(onCommit:onRollback:)&lt;/a&gt;. For example:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct PictureFile: PersistableRecord {
    var path: String
    
    func willDelete(_ db: Database) {
        db.afterNextTransaction { _ in
            try? deleteFileOnDisk()
        }
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Identifiable Records&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;When a record type maps a table with a single-column primary key, it is recommended to have it adopt the standard &lt;a href=&quot;https://developer.apple.com/documentation/swift/identifiable&quot;&gt;Identifiable&lt;/a&gt; protocol.&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Identifiable, FetchableRecord, PersistableRecord {
    var id: Int64 // fulfills the Identifiable requirement
    var name: String
    var score: Int
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When &lt;code&gt;id&lt;/code&gt; has a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;database-compatible type&lt;/a&gt; (Int64, Int, String, UUID, ...), the &lt;code&gt;Identifiable&lt;/code&gt; conformance unlocks type-safe record and request methods:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let player = try Player.find(db, id: 1)               // Player
let player = try Player.fetchOne(db, id: 1)           // Player?
let players = try Player.fetchAll(db, ids: [1, 2, 3]) // [Player]
let players = try Player.fetchSet(db, ids: [1, 2, 3]) // Set&amp;lt;Player&amp;gt;

let request = Player.filter(id: 1)
let request = Player.filter(ids: [1, 2, 3])

try Player.deleteOne(db, id: 1)
try Player.deleteAll(db, ids: [1, 2, 3])
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Not all record types can be made &lt;code&gt;Identifiable&lt;/code&gt;, and not all tables have a single-column primary key. GRDB provides other methods that deal with primary and unique keys, but they won&#39;t check the type of their arguments:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Available on non-Identifiable types
try Player.fetchOne(db, key: 1)
try Player.fetchOne(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
try Country.fetchAll(db, keys: [&quot;FR&quot;, &quot;US&quot;])
try Citizenship.fetchOne(db, key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;])

let request = Player.filter(key: 1)
let request = Player.filter(keys: [1, 2, 3])

try Player.deleteOne(db, key: 1)
try Player.deleteAll(db, keys: [1, 2, 3])
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: It is not recommended to use &lt;code&gt;Identifiable&lt;/code&gt; on record types that use an auto-incremented primary key:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// AVOID declaring Identifiable conformance when key is auto-incremented
struct Player {
    var id: Int64? // Not an id suitable for Identifiable
    var name: String
    var score: Int
}

extension Player: FetchableRecord, MutablePersistableRecord {
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;For a detailed rationale, please see &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues/1435#issuecomment-1740857712&quot;&gt;issue #1435&lt;/a&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;Some database tables have a single-column primary key which is not called &quot;id&quot;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try db.create(table: &quot;country&quot;) { t in
    t.primaryKey(&quot;isoCode&quot;, .text)
    t.column(&quot;name&quot;, .text).notNull()
    t.column(&quot;population&quot;, .integer).notNull()
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;In this case, &lt;code&gt;Identifiable&lt;/code&gt; conformance can be achieved, for example, by returning the primary key column from the &lt;code&gt;id&lt;/code&gt; property:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Country: Identifiable, FetchableRecord, PersistableRecord {
    var isoCode: String
    var name: String
    var population: Int
    
    // Fulfill the Identifiable requirement
    var id: String { isoCode }
}

let france = try dbQueue.read { db in
    try Country.fetchOne(db, id: &quot;FR&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Codable Records&lt;/h2&gt; 
&lt;p&gt;Record types that adopt an archival protocol (&lt;a href=&quot;https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types&quot;&gt;Codable, Encodable or Decodable&lt;/a&gt;) get free database support just by declaring conformance to the desired &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;record protocols&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Declare a record...
struct Player: Codable, FetchableRecord, PersistableRecord {
    var id: Int64
    var name: String
    var score: Int
    
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}

// ...and there you go:
try dbQueue.write { db in
    try Player(id: 1, name: &quot;Arthur&quot;, score: 100).insert(db)
    let players = try Player.order(\.score.desc).fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Codable records encode and decode their properties according to their own implementation of the Encodable and Decodable protocols. Yet databases have specific requirements:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Properties are always coded according to their preferred database representation, when they have one (all &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;values&lt;/a&gt; that adopt the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt; protocol).&lt;/li&gt; 
 &lt;li&gt;You can customize the encoding and decoding of dates and uuids.&lt;/li&gt; 
 &lt;li&gt;Complex properties (arrays, dictionaries, nested structs, etc.) are stored as JSON.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;For more information about Codable records, see:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#json-columns&quot;&gt;JSON Columns&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#column-names-coding-strategies&quot;&gt;Column Names Coding Strategies&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#data-date-and-uuid-coding-strategies&quot;&gt;Data, Date, and UUID Coding Strategies&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-userinfo-dictionary&quot;&gt;The userInfo Dictionary&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tip-derive-columns-from-coding-keys&quot;&gt;Tip: Derive Columns from Coding Keys&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;: see the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/DemoApps&quot;&gt;Demo Applications&lt;/a&gt; for sample code that uses Codable records.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;JSON Columns&lt;/h3&gt; 
&lt;p&gt;When a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable record&lt;/a&gt; contains a property that is not a simple &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;value&lt;/a&gt; (Bool, Int, String, Date, Swift enums, etc.), that value is encoded and decoded as a &lt;strong&gt;JSON string&lt;/strong&gt;. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;enum AchievementColor: String, Codable {
    case bronze, silver, gold
}

struct Achievement: Codable {
    var name: String
    var color: AchievementColor
}

struct Player: Codable, FetchableRecord, PersistableRecord {
    var name: String
    var score: Int
    var achievements: [Achievement] // stored in a JSON column
}

try dbQueue.write { db in
    // INSERT INTO player (name, score, achievements)
    // VALUES (
    //   &#39;Arthur&#39;,
    //   100,
    //   &#39;[{&quot;color&quot;:&quot;gold&quot;,&quot;name&quot;:&quot;Use Codable Records&quot;}]&#39;)
    let achievement = Achievement(name: &quot;Use Codable Records&quot;, color: .gold)
    let player = Player(name: &quot;Arthur&quot;, score: 100, achievements: [achievement])
    try player.insert(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;GRDB uses the standard &lt;a href=&quot;https://developer.apple.com/documentation/foundation/jsondecoder&quot;&gt;JSONDecoder&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/foundation/jsonencoder&quot;&gt;JSONEncoder&lt;/a&gt; from Foundation. By default, Data values are handled with the &lt;code&gt;.base64&lt;/code&gt; strategy, Date with the &lt;code&gt;.millisecondsSince1970&lt;/code&gt; strategy, and non conforming floats with the &lt;code&gt;.throw&lt;/code&gt; strategy.&lt;/p&gt; 
&lt;p&gt;You can customize the JSON format by implementing those methods:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol FetchableRecord {
    static func databaseJSONDecoder(for column: String) -&amp;gt; JSONDecoder
}

protocol EncodableRecord {
    static func databaseJSONEncoder(for column: String) -&amp;gt; JSONEncoder
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;: Make sure you set the JSONEncoder &lt;code&gt;sortedKeys&lt;/code&gt; option. This option makes sure that the JSON output is stable. This stability is required for &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;Record Comparison&lt;/a&gt; to work as expected, and database observation tools such as &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/valueobservation&quot;&gt;ValueObservation&lt;/a&gt; to accurately recognize changed records.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;Column Names Coding Strategies&lt;/h3&gt; 
&lt;p&gt;By default, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; store their values into database columns that match their coding keys: the &lt;code&gt;teamID&lt;/code&gt; property is stored into the &lt;code&gt;teamID&lt;/code&gt; column.&lt;/p&gt; 
&lt;p&gt;This behavior can be overridden, so that you can, for example, store the &lt;code&gt;teamID&lt;/code&gt; property into the &lt;code&gt;team_id&lt;/code&gt; column:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol FetchableRecord {
    static var databaseColumnDecodingStrategy: DatabaseColumnDecodingStrategy { get }
}

protocol EncodableRecord {
    static var databaseColumnEncodingStrategy: DatabaseColumnEncodingStrategy { get }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasecolumndecodingstrategy&quot;&gt;DatabaseColumnDecodingStrategy&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasecolumnencodingstrategy/&quot;&gt;DatabaseColumnEncodingStrategy&lt;/a&gt; to learn about all available strategies.&lt;/p&gt; 
&lt;h3&gt;Data, Date, and UUID Coding Strategies&lt;/h3&gt; 
&lt;p&gt;By default, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; encode and decode their Data properties as blobs, and Date and UUID properties as described in the general &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#date-and-datecomponents&quot;&gt;Date and DateComponents&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#uuid&quot;&gt;UUID&lt;/a&gt; chapters.&lt;/p&gt; 
&lt;p&gt;To sum up: dates encode themselves in the &quot;YYYY-MM-DD HH:MM:SS.SSS&quot; format, in the UTC time zone, and decode a variety of date formats and timestamps. UUIDs encode themselves as 16-bytes data blobs, and decode both 16-bytes data blobs and strings such as &quot;E621E1F8-C36C-495A-93FC-0C247A3E6E5F&quot;.&lt;/p&gt; 
&lt;p&gt;Those behaviors can be overridden:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol FetchableRecord {
    static func databaseDataDecodingStrategy(for column: String) -&amp;gt; DatabaseDataDecodingStrategy
    static func databaseDateDecodingStrategy(for column: String) -&amp;gt; DatabaseDateDecodingStrategy
}

protocol EncodableRecord {
    static func databaseDataEncodingStrategy(for column: String) -&amp;gt; DatabaseDataEncodingStrategy
    static func databaseDateEncodingStrategy(for column: String) -&amp;gt; DatabaseDateEncodingStrategy
    static func databaseUUIDEncodingStrategy(for column: String) -&amp;gt; DatabaseUUIDEncodingStrategy
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasedatadecodingstrategy/&quot;&gt;DatabaseDataDecodingStrategy&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasedatedecodingstrategy/&quot;&gt;DatabaseDateDecodingStrategy&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasedataencodingstrategy/&quot;&gt;DatabaseDataEncodingStrategy&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasedateencodingstrategy/&quot;&gt;DatabaseDateEncodingStrategy&lt;/a&gt;, and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseuuidencodingstrategy/&quot;&gt;DatabaseUUIDEncodingStrategy&lt;/a&gt; to learn about all available strategies.&lt;/p&gt; 
&lt;p&gt;There is no customization of uuid decoding, because UUID can already decode all its encoded variants (16-bytes blobs and uuid strings, both uppercase and lowercase).&lt;/p&gt; 
&lt;p&gt;Customized coding strategies apply:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;When encoding and decoding database rows to and from records (fetching and persistence methods).&lt;/li&gt; 
 &lt;li&gt;In requests by single-column primary key: &lt;code&gt;fetchOne(_&lt;span&gt;🆔&lt;/span&gt;)&lt;/code&gt;, &lt;code&gt;filter(id:)&lt;/code&gt;, &lt;code&gt;deleteAll(_:keys:)&lt;/code&gt;, etc.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;em&gt;They do not apply&lt;/em&gt; in other requests based on data, date, or uuid values.&lt;/p&gt; 
&lt;p&gt;So make sure that those are properly encoded in your requests. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Codable, FetchableRecord, PersistableRecord, Identifiable {
    // UUIDs are stored as strings
    static func databaseUUIDEncodingStrategy(for column: String) -&amp;gt; DatabaseUUIDEncodingStrategy {
        .uppercaseString
    }
    
    var id: UUID
    ...
}

try dbQueue.write { db in
    let uuid = UUID()
    let player = Player(id: uuid, ...)
    
    // OK: inserts a player in the database, with a string uuid
    try player.insert(db)
    
    // OK: performs a string-based query, finds the inserted player
    _ = try Player.filter(id: uuid).fetchOne(db)

    // NOT OK: performs a blob-based query, fails to find the inserted player
    _ = try Player.filter { $0.id == uuid }.fetchOne(db)
    
    // OK: performs a string-based query, finds the inserted player
    _ = try Player.filter { $0.id == uuid.uuidString }.fetchOne(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;The userInfo Dictionary&lt;/h3&gt; 
&lt;p&gt;Your &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; can be stored in the database, but they may also have other purposes. In this case, you may need to customize their implementations of &lt;code&gt;Decodable.init(from:)&lt;/code&gt; and &lt;code&gt;Encodable.encode(to:)&lt;/code&gt;, depending on the context.&lt;/p&gt; 
&lt;p&gt;The standard way to provide such context is the &lt;code&gt;userInfo&lt;/code&gt; dictionary. Implement those properties:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol FetchableRecord {
    static var databaseDecodingUserInfo: [CodingUserInfoKey: Any] { get }
}

protocol EncodableRecord {
    static var databaseEncodingUserInfo: [CodingUserInfoKey: Any] { get }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For example, here is a Player type that customizes its decoding:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// A key that holds a decoder&#39;s name
let decoderName = CodingUserInfoKey(rawValue: &quot;decoderName&quot;)!

struct Player: FetchableRecord, Decodable {
    init(from decoder: Decoder) throws {
        // Print the decoder name
        let decoderName = decoder.userInfo[decoderName] as? String
        print(&quot;Decoded from \(decoderName ?? &quot;unknown decoder&quot;)&quot;)
        ...
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can have a specific decoding from JSON...&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// prints &quot;Decoded from JSON&quot;
let decoder = JSONDecoder()
decoder.userInfo = [decoderName: &quot;JSON&quot;]
let player = try decoder.decode(Player.self, from: jsonData)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;... and another one from database rows:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Player: FetchableRecord {
    static var databaseDecodingUserInfo: [CodingUserInfoKey: Any] {
        [decoderName: &quot;database row&quot;]
    }
}

// prints &quot;Decoded from database row&quot;
let player = try Player.fetchOne(db, ...)
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: make sure the &lt;code&gt;databaseDecodingUserInfo&lt;/code&gt; and &lt;code&gt;databaseEncodingUserInfo&lt;/code&gt; properties are explicitly declared as &lt;code&gt;[CodingUserInfoKey: Any]&lt;/code&gt;. If they are not, the Swift compiler may silently miss the protocol requirement, resulting in sticky empty userInfo.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;Tip: Derive Columns from Coding Keys&lt;/h3&gt; 
&lt;p&gt;Codable types are granted with a &lt;a href=&quot;https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types&quot;&gt;CodingKeys&lt;/a&gt; enum. You can use them to safely define database columns:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: Codable {
    var id: Int64
    var name: String
    var score: Int
}

extension Player: FetchableRecord, PersistableRecord {
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recordrecommendedpractices&quot;&gt;Recommended Practices for Designing Record Types&lt;/a&gt; for further information.&lt;/p&gt; 
&lt;h2&gt;Record Comparison&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Records that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;EncodableRecord&lt;/a&gt; protocol can compare against other records, or against previous versions of themselves.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;This helps avoiding costly UPDATE statements when a record has not been edited.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-updatechanges-methods&quot;&gt;The &lt;code&gt;updateChanges&lt;/code&gt; Methods&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-databaseequals-method&quot;&gt;The &lt;code&gt;databaseEquals&lt;/code&gt; Method&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-databasechanges-and-hasdatabasechanges-methods&quot;&gt;The &lt;code&gt;databaseChanges&lt;/code&gt; and &lt;code&gt;hasDatabaseChanges&lt;/code&gt; Methods&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;The &lt;code&gt;updateChanges&lt;/code&gt; Methods&lt;/h3&gt; 
&lt;p&gt;The &lt;code&gt;updateChanges&lt;/code&gt; methods perform a database update of the changed columns only (and does nothing if record has no change).&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;updateChanges(_:from:)&lt;/code&gt;&lt;/p&gt; &lt;p&gt;This method lets you compare two records:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;if let oldPlayer = try Player.fetchOne(db, id: 42) {
    var newPlayer = oldPlayer
    newPlayer.score = 100
    if try newPlayer.updateChanges(db, from: oldPlayer) {
        print(&quot;player was modified, and updated in the database&quot;)
    } else {
        print(&quot;player was not modified, and database was not hit&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;updateChanges(_:modify:)&lt;/code&gt;&lt;/p&gt; &lt;p&gt;This method lets you update a record in place:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;if var player = try Player.fetchOne(db, id: 42) {
    let modified = try player.updateChanges(db) {
        $0.score = 100
    }
    if modified {
        print(&quot;player was modified, and updated in the database&quot;)
    } else {
        print(&quot;player was not modified, and database was not hit&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;The &lt;code&gt;databaseEquals&lt;/code&gt; Method&lt;/h3&gt; 
&lt;p&gt;This method returns whether two records have the same database representation:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let oldPlayer: Player = ...
var newPlayer: Player = ...
if newPlayer.databaseEquals(oldPlayer) == false {
    try newPlayer.save(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The comparison is performed on the database representation of records. As long as your record type adopts the EncodableRecord protocol, you don&#39;t need to care about Equatable.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;The &lt;code&gt;databaseChanges&lt;/code&gt; and &lt;code&gt;hasDatabaseChanges&lt;/code&gt; Methods&lt;/h3&gt; 
&lt;p&gt;&lt;code&gt;databaseChanges(from:)&lt;/code&gt; returns a dictionary of differences between two records:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let oldPlayer = Player(id: 1, name: &quot;Arthur&quot;, score: 100)
let newPlayer = Player(id: 1, name: &quot;Arthur&quot;, score: 1000)
for (column, oldValue) in try newPlayer.databaseChanges(from: oldPlayer) {
    print(&quot;\(column) was \(oldValue)&quot;)
}
// prints &quot;score was 100&quot;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For an efficient algorithm which synchronizes the content of a database table with a JSON payload, check &lt;a href=&quot;https://github.com/groue/SortedDifference&quot;&gt;groue/SortedDifference&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Record Customization Options&lt;/h2&gt; 
&lt;p&gt;GRDB records come with many default behaviors, that are designed to fit most situations. Many of those defaults can be customized for your specific needs:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;Persistence Callbacks&lt;/a&gt;: define what happens when you call a persistence method such as &lt;code&gt;player.insert(db)&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#conflict-resolution&quot;&gt;Conflict Resolution&lt;/a&gt;: Run &lt;code&gt;INSERT OR REPLACE&lt;/code&gt; queries, and generally define what happens when a persistence method violates a unique index.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#columns-selected-by-a-request&quot;&gt;Columns Selected by a Request&lt;/a&gt;: define which columns are selected by requests such as &lt;code&gt;Player.fetchAll(db)&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#beyond-fetchablerecord&quot;&gt;Beyond FetchableRecord&lt;/a&gt;: the FetchableRecord protocol is not the end of the story.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; have a few extra options:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#json-columns&quot;&gt;JSON Columns&lt;/a&gt;: control the format of JSON columns.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#column-names-coding-strategies&quot;&gt;Column Names Coding Strategies&lt;/a&gt;: control how coding keys are turned into column names&lt;/li&gt; 
 &lt;li&gt;[Date and UUID Coding Strategies]: control the format of Date and UUID properties in your Codable records.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-userinfo-dictionary&quot;&gt;The userInfo Dictionary&lt;/a&gt;: adapt your Codable implementation for the database.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Conflict Resolution&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Insertions and updates can create conflicts&lt;/strong&gt;: for example, a query may attempt to insert a duplicate row that violates a unique index.&lt;/p&gt; 
&lt;p&gt;Those conflicts normally end with an error. Yet SQLite let you alter the default behavior, and handle conflicts with specific policies. For example, the &lt;code&gt;INSERT OR REPLACE&lt;/code&gt; statement handles conflicts with the &quot;replace&quot; policy which replaces the conflicting row instead of throwing an error.&lt;/p&gt; 
&lt;p&gt;The &lt;a href=&quot;https://www.sqlite.org/lang_conflict.html&quot;&gt;five different policies&lt;/a&gt; are: abort (the default), replace, rollback, fail, and ignore.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;SQLite let you specify conflict policies at two different places:&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;In the definition of the database table:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// CREATE TABLE player (
//     id INTEGER PRIMARY KEY AUTOINCREMENT,
//     email TEXT UNIQUE ON CONFLICT REPLACE
// )
try db.create(table: &quot;player&quot;) { t in
    t.autoIncrementedPrimaryKey(&quot;id&quot;)
    t.column(&quot;email&quot;, .text).unique(onConflict: .replace) // &amp;lt;--
}

// Despite the unique index on email, both inserts succeed.
// The second insert replaces the first row:
try db.execute(sql: &quot;INSERT INTO player (email) VALUES (?)&quot;, arguments: [&quot;arthur@example.com&quot;])
try db.execute(sql: &quot;INSERT INTO player (email) VALUES (?)&quot;, arguments: [&quot;arthur@example.com&quot;])
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;In each modification query:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// CREATE TABLE player (
//     id INTEGER PRIMARY KEY AUTOINCREMENT,
//     email TEXT UNIQUE
// )
try db.create(table: &quot;player&quot;) { t in
    t.autoIncrementedPrimaryKey(&quot;id&quot;)
    t.column(&quot;email&quot;, .text).unique()
}

// Again, despite the unique index on email, both inserts succeed.
try db.execute(sql: &quot;INSERT OR REPLACE INTO player (email) VALUES (?)&quot;, arguments: [&quot;arthur@example.com&quot;])
try db.execute(sql: &quot;INSERT OR REPLACE INTO player (email) VALUES (?)&quot;, arguments: [&quot;arthur@example.com&quot;])
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;When you want to handle conflicts at the query level, specify a custom &lt;code&gt;persistenceConflictPolicy&lt;/code&gt; in your type that adopts the PersistableRecord protocol. It will alter the INSERT and UPDATE queries run by the &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;save&lt;/code&gt; &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-methods&quot;&gt;persistence methods&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;protocol MutablePersistableRecord {
    /// The policy that handles SQLite conflicts when records are
    /// inserted or updated.
    ///
    /// This property is optional: its default value uses the ABORT
    /// policy for both insertions and updates, so that GRDB generate
    /// regular INSERT and UPDATE queries.
    static var persistenceConflictPolicy: PersistenceConflictPolicy { get }
}

struct Player : MutablePersistableRecord {
    static let persistenceConflictPolicy = PersistenceConflictPolicy(
        insert: .replace,
        update: .replace)
}

// INSERT OR REPLACE INTO player (...) VALUES (...)
try player.insert(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you specify the &lt;code&gt;ignore&lt;/code&gt; policy for inserts, the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;&lt;code&gt;didInsert&lt;/code&gt; callback&lt;/a&gt; will be called with some random id in case of failed insert. You can detect failed insertions with &lt;code&gt;insertAndFetch&lt;/code&gt;:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// How to detect failed `INSERT OR IGNORE`:
// INSERT OR IGNORE INTO player ... RETURNING *
do {
    let insertedPlayer = try player.insertAndFetch(db) {
    // Successful insertion
catch RecordError.recordNotFound {
    // Failed insertion due to IGNORE policy
}
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The &lt;code&gt;replace&lt;/code&gt; policy may have to delete rows so that inserts and updates can succeed. Those deletions are not reported to &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/transactionobserver&quot;&gt;transaction observers&lt;/a&gt; (this might change in a future release of SQLite).&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;Beyond FetchableRecord&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Some GRDB users eventually discover that the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; protocol does not fit all situations.&lt;/strong&gt; Use cases that are not well handled by FetchableRecord include:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;Your application needs polymorphic row decoding: it decodes some type or another, depending on the values contained in a database row.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Your application needs to decode rows with a context: each decoded value should be initialized with some extra value that does not come from the database.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Since those use cases are not well handled by FetchableRecord, don&#39;t try to implement them on top of this protocol: you&#39;ll just fight the framework.&lt;/p&gt; 
&lt;h2&gt;Examples of Record Definitions&lt;/h2&gt; 
&lt;p&gt;We will show below how to declare a record type for the following database table:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try db.create(table: &quot;place&quot;) { t in
        t.autoIncrementedPrimaryKey(&quot;id&quot;)
        t.column(&quot;title&quot;, .text).notNull()
        t.column(&quot;isFavorite&quot;, .boolean).notNull().defaults(to: false)
        t.column(&quot;longitude&quot;, .double).notNull()
        t.column(&quot;latitude&quot;, .double).notNull()
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Each one of the three examples below is correct. You will pick one or the other depending on your personal preferences and the requirements of your application:&lt;/p&gt; 
&lt;details&gt; 
 &lt;summary&gt;Define a Codable struct, and adopt the record protocols you need&lt;/summary&gt; 
 &lt;p&gt;This is the shortest way to define a record type.&lt;/p&gt; 
 &lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;Record Protocols Overview&lt;/a&gt;, and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt; for more information.&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: Codable {
    var id: Int64?
    var title: String
    var isFavorite: Bool
    private var latitude: CLLocationDegrees
    private var longitude: CLLocationDegrees
    
    var coordinate: CLLocationCoordinate2D {
        get {
            CLLocationCoordinate2D(
                latitude: latitude,
                longitude: longitude)
        }
        set {
            latitude = newValue.latitude
            longitude = newValue.longitude
        }
    }
}

// SQL generation
extension Place: TableRecord {
    /// The table columns
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let title = Column(CodingKeys.title)
        static let isFavorite = Column(CodingKeys.isFavorite)
        static let latitude = Column(CodingKeys.latitude)
        static let longitude = Column(CodingKeys.longitude)
    }
}

// Fetching methods
extension Place: FetchableRecord { }

// Persistence methods
extension Place: MutablePersistableRecord {
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Define a plain struct, and adopt the record protocols you need&lt;/summary&gt; 
 &lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;Record Protocols Overview&lt;/a&gt; for more information.&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place {
    var id: Int64?
    var title: String
    var isFavorite: Bool
    var coordinate: CLLocationCoordinate2D
}

// SQL generation
extension Place: TableRecord {
    /// The table columns
    enum Columns {
        static let id = Column(&quot;id&quot;)
        static let title = Column(&quot;title&quot;)
        static let isFavorite = Column(&quot;isFavorite&quot;)
        static let latitude = Column(&quot;latitude&quot;)
        static let longitude = Column(&quot;longitude&quot;)
    }
}

// Fetching methods
extension Place: FetchableRecord {
    /// Creates a record from a database row
    init(row: Row) {
        id = row[Columns.id]
        title = row[Columns.title]
        isFavorite = row[Columns.isFavorite]
        coordinate = CLLocationCoordinate2D(
            latitude: row[Columns.latitude],
            longitude: row[Columns.longitude])
    }
}

// Persistence methods
extension Place: MutablePersistableRecord {
    /// The values persisted in the database
    func encode(to container: inout PersistenceContainer) {
        container[Columns.id] = id
        container[Columns.title] = title
        container[Columns.isFavorite] = isFavorite
        container[Columns.latitude] = coordinate.latitude
        container[Columns.longitude] = coordinate.longitude
    }
    
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Define a plain struct optimized for fetching performance&lt;/summary&gt; 
 &lt;p&gt;This struct derives its persistence methods from the standard Encodable protocol (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#codable-records&quot;&gt;Codable Records&lt;/a&gt;), but performs optimized row decoding by accessing database columns with numeric indexes.&lt;/p&gt; 
 &lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-protocols-overview&quot;&gt;Record Protocols Overview&lt;/a&gt; for more information.&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Place: Encodable {
    var id: Int64?
    var title: String
    var isFavorite: Bool
    private var latitude: CLLocationDegrees
    private var longitude: CLLocationDegrees
    
    var coordinate: CLLocationCoordinate2D {
        get {
            CLLocationCoordinate2D(
                latitude: latitude,
                longitude: longitude)
        }
        set {
            latitude = newValue.latitude
            longitude = newValue.longitude
        }
    }
}

// SQL generation
extension Place: TableRecord {
    /// The table columns
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let title = Column(CodingKeys.title)
        static let isFavorite = Column(CodingKeys.isFavorite)
        static let latitude = Column(CodingKeys.latitude)
        static let longitude = Column(CodingKeys.longitude)
    }
    
    /// Arrange the selected columns and lock their order
    static var databaseSelection: [any SQLSelectable] {
        [
            Columns.id,
            Columns.title,
            Columns.favorite,
            Columns.latitude,
            Columns.longitude,
        ]
    }
}

// Fetching methods
extension Place: FetchableRecord {
    /// Creates a record from a database row
    init(row: Row) {
        // For high performance, use numeric indexes that match the
        // order of Place.databaseSelection
        id = row[0]
        title = row[1]
        isFavorite = row[2]
        coordinate = CLLocationCoordinate2D(
            latitude: row[3],
            longitude: row[4])
    }
}

// Persistence methods
extension Place: MutablePersistableRecord {
    // Update auto-incremented id upon successful insertion
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;h1&gt;The Query Interface&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;The query interface lets you write pure Swift instead of SQL:&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    // Update database schema
    try db.create(table: &quot;player&quot;) { t in ... }
    
    // Fetch records
    let bestPlayers = try Player
        .order(\.score.desc)
        .limit(10)
        .fetchAll(db)
    
    // Count
    let count = try Player
        .filter { $0.score &amp;gt;= 1000 }
        .fetchCount(db)
    
    // Batch update
    try Player
        .filter { $0.team == &quot;Reds&quot; }
        .updateAll(db) { $0.score += 100 }
    
    // Batch delete
    try Player
        .filter { $0.score == 0 }
        .deleteAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You need to open a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;database connection&lt;/a&gt; before you can query the database.&lt;/p&gt; 
&lt;p&gt;Please bear in mind that the query interface can not generate all possible SQL queries. You may also &lt;em&gt;prefer&lt;/em&gt; writing SQL, and this is just OK. From little snippets to full queries, your SQL skills are welcome:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    // Update database schema (with SQL)
    try db.execute(sql: &quot;CREATE TABLE player (...)&quot;)
    
    // Fetch records (with SQL)
    let bestPlayers = try Player.fetchAll(db, sql: &quot;&quot;&quot;
        SELECT * FROM player ORDER BY score DESC LIMIT 10
        &quot;&quot;&quot;)
    
    // Count (with an SQL snippet)
    let minScore = 1000
    let count = try Player
        .filter(sql: &quot;score &amp;gt;= ?&quot;, arguments: [minScore])
        .fetchCount(db)
    
    // Update (with SQL)
    try db.execute(sql: &quot;UPDATE player SET score = score + 100 WHERE team = &#39;Reds&#39;&quot;)
    
    // Delete (with SQL)
    try db.execute(sql: &quot;DELETE FROM player WHERE score = 0&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;So don&#39;t miss the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-api&quot;&gt;SQL API&lt;/a&gt;.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: the generated SQL may change between GRDB releases, without notice: don&#39;t have your application rely on any specific SQL output.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseschema&quot;&gt;The Database Schema&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#requests&quot;&gt;Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#expressions&quot;&gt;Expressions&lt;/a&gt; 
  &lt;ul&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sql-operators&quot;&gt;SQL Operators&lt;/a&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sql-functions&quot;&gt;SQL Functions&lt;/a&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#embedding-sql-in-query-interface-requests&quot;&gt;Embedding SQL in Query Interface Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-from-requests&quot;&gt;Fetching from Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-by-key&quot;&gt;Fetching by Key&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#testing-for-record-existence&quot;&gt;Testing for Record Existence&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-aggregated-values&quot;&gt;Fetching Aggregated Values&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#delete-requests&quot;&gt;Delete Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#update-requests&quot;&gt;Update Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-requests&quot;&gt;Custom Requests&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;📘 &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations and Joins&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;📘 &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CommonTableExpressions.md&quot;&gt;Common Table Expressions&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;📘 &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/QueryInterfaceOrganization.md&quot;&gt;Query Interface Organization&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Requests&lt;/h2&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest&quot;&gt;&lt;code&gt;QueryInterfaceRequest&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/table&quot;&gt;&lt;code&gt;Table&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;The query interface requests&lt;/strong&gt; let you fetch values from the database:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.filter { $0.email != nil }.order(\.name)
let players = try request.fetchAll(db)  // [Player]
let count = try request.fetchCount(db)  // Int
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Query interface requests usually start from &lt;strong&gt;a type&lt;/strong&gt; that adopts the &lt;code&gt;TableRecord&lt;/code&gt; protocol:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: TableRecord { ... }

// The request for all players:
let request = Player.all()
let players = try request.fetchAll(db) // [Player]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When you can not use a record type, use &lt;code&gt;Table&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// The request for all rows from the player table:
let table = Table(&quot;player&quot;)
let request = table.all()
let rows = try request.fetchAll(db)    // [Row]

// The request for all players from the player table:
let table = Table&amp;lt;Player&amp;gt;(&quot;player&quot;)
let request = table.all()
let players = try request.fetchAll(db) // [Player]
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: all examples in the documentation below use a record type, but you can always substitute a &lt;code&gt;Table&lt;/code&gt; instead.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;Next, declare the table &lt;strong&gt;columns&lt;/strong&gt; that you want to use for filtering, or sorting, in a nested type named &lt;code&gt;Columns&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Player {
    enum Columns {
        static let id = Column(&quot;id&quot;)
        static let name = Column(&quot;name&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When &lt;code&gt;Player&lt;/code&gt; is &lt;code&gt;Codable&lt;/code&gt;, you&#39;ll prefer defining columns from coding keys:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Player {
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can now build requests with the following methods: &lt;code&gt;all&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;matching&lt;/code&gt;, &lt;code&gt;group&lt;/code&gt;, &lt;code&gt;having&lt;/code&gt;, &lt;code&gt;order&lt;/code&gt;, &lt;code&gt;reversed&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt;, &lt;code&gt;joining&lt;/code&gt;, &lt;code&gt;including&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;. All those methods return another request, which you can further refine by applying another method: &lt;code&gt;Player.select(...).filter(...).order(...)&lt;/code&gt;.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerecord/all()&quot;&gt;&lt;code&gt;all()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerecord/none()&quot;&gt;&lt;code&gt;none()&lt;/code&gt;&lt;/a&gt;: the requests for all rows, or no row.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player
Player.all()
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;By default, all columns are selected. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#columns-selected-by-a-request&quot;&gt;Columns Selected by a Request&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/selectionrequest/select(_:)-ruzy&quot;&gt;&lt;code&gt;select(...)&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest/select(_:as:)-58954&quot;&gt;&lt;code&gt;select(..., as:)&lt;/code&gt;&lt;/a&gt; define the selected columns. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#columns-selected-by-a-request&quot;&gt;Columns Selected by a Request&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT name FROM player
Player.select(\.name, as: String.self)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest/selectID()&quot;&gt;&lt;code&gt;selectID()&lt;/code&gt;&lt;/a&gt; is available on &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt;. It supports all tables that have a single-column primary key:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT id FROM player
Player.selectID()

// SELECT id FROM player WHERE name IS NOT NULL
Player.filter { $0.name != nil }.selectID()
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/selectionrequest/annotated(with:)-1satx&quot;&gt;&lt;code&gt;annotated(with: expression...)&lt;/code&gt;&lt;/a&gt; extends the selection.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT *, (score + bonus) AS total FROM player
Player.annotated { ($0.score + $0.bonus).forKey(&quot;total&quot;) }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/derivablerequest/annotated(with:)-74xfs&quot;&gt;&lt;code&gt;annotated(with: aggregate)&lt;/code&gt;&lt;/a&gt; extends the selection with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md#association-aggregates&quot;&gt;association aggregates&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT team.*, COUNT(DISTINCT player.id) AS playerCount
// FROM team
// LEFT JOIN player ON player.teamId = team.id
// GROUP BY team.id
Team.annotated(with: Team.players.count)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/annotated(withrequired:)&quot;&gt;&lt;code&gt;annotated(withRequired: association)&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/annotated(withoptional:)&quot;&gt;&lt;code&gt;annotated(withOptional: association)&lt;/code&gt;&lt;/a&gt; extends the selection with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT player.*, team.color
// FROM player
// JOIN team ON team.id = player.teamId
Player.annotated(withRequired: Player.team.select(\.color))
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/derivablerequest/distinct()&quot;&gt;&lt;code&gt;distinct()&lt;/code&gt;&lt;/a&gt; performs uniquing.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT DISTINCT name FROM player
Player.select(\.name, as: String.self).distinct()
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/filteredrequest/filter(_:)-6xr3d&quot;&gt;&lt;code&gt;filter(expression)&lt;/code&gt;&lt;/a&gt; applies conditions.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE id IN (1, 2, 3)
Player.filter { [1,2,3].contains($0.id) }

// SELECT * FROM player WHERE (name IS NOT NULL) AND (height &amp;gt; 1.75)
Player.filter { $0.name != nil &amp;amp;&amp;amp; $0.height &amp;gt; 1.75 }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/filter(id:)&quot;&gt;&lt;code&gt;filter(id:)&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/filter(ids:)&quot;&gt;&lt;code&gt;filter(ids:)&lt;/code&gt;&lt;/a&gt; are type-safe methods available on &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE id = 1
Player.filter(id: 1)

// SELECT * FROM country WHERE isoCode IN (&#39;FR&#39;, &#39;US&#39;)
Country.filter(ids: [&quot;FR&quot;, &quot;US&quot;])
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/filter(key:)-1p9sq&quot;&gt;&lt;code&gt;filter(key:)&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/filter(keys:)-6ggt1&quot;&gt;&lt;code&gt;filter(keys:)&lt;/code&gt;&lt;/a&gt; apply conditions on primary and unique keys:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE id = 1
Player.filter(key: 1)

// SELECT * FROM country WHERE isoCode IN (&#39;FR&#39;, &#39;US&#39;)
Country.filter(keys: [&quot;FR&quot;, &quot;US&quot;])

// SELECT * FROM citizenship WHERE citizenId = 1 AND countryCode = &#39;FR&#39;
Citizenship.filter(key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;])

// SELECT * FROM player WHERE email = &#39;arthur@example.com&#39;
Player.filter(key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;matching(pattern)&lt;/code&gt; (&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/matching(_:)-3s3zr&quot;&gt;FTS3&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/matching(_:)-7c1e8&quot;&gt;FTS5&lt;/a&gt;) performs &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md&quot;&gt;full-text search&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM document WHERE document MATCH &#39;sqlite database&#39;
let pattern = FTS3Pattern(matchingAllTokensIn: &quot;SQLite database&quot;)
Document.matching(pattern)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When the pattern is nil, no row will match.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/aggregatingrequest/group(_:)-2g7br&quot;&gt;&lt;code&gt;group(expression, ...)&lt;/code&gt;&lt;/a&gt; groups rows.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT name, MAX(score) FROM player GROUP BY name
Player
    .select { [$0.name, max($0.score)] }
    .group(\.name)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/aggregatingrequest/having(_:)-2oggh&quot;&gt;&lt;code&gt;having(expression)&lt;/code&gt;&lt;/a&gt; applies conditions on grouped rows.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT team, MAX(score) FROM player GROUP BY team HAVING MIN(score) &amp;gt;= 1000
Player
    .select { [$0.team, max($0.score)] }
    .group(\.team)
    .having { min($0.score) &amp;gt;= 1000 }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/derivablerequest/having(_:)&quot;&gt;&lt;code&gt;having(aggregate)&lt;/code&gt;&lt;/a&gt; applies conditions on grouped rows, according to an &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md#association-aggregates&quot;&gt;association aggregate&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT team.*
// FROM team
// LEFT JOIN player ON player.teamId = team.id
// GROUP BY team.id
// HAVING COUNT(DISTINCT player.id) &amp;gt;= 5
Team.having(Team.players.count &amp;gt;= 5)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/orderedrequest/order(_:)-9d0hr&quot;&gt;&lt;code&gt;order(ordering, ...)&lt;/code&gt;&lt;/a&gt; sorts.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player ORDER BY name
Player.order(\.name)

// SELECT * FROM player ORDER BY score DESC
Player.order(\.score.desc)

// SELECT * FROM player ORDER BY score DESC, name
Player.order { [$0.score.desc, $0.name] }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;SQLite considers NULL values to be smaller than any other values for sorting purposes. Hence, NULLs naturally appear at the beginning of an ascending ordering and at the end of a descending ordering. With a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CustomSQLiteBuilds.md&quot;&gt;custom SQLite build&lt;/a&gt;, this can be changed using &lt;code&gt;.ascNullsLast&lt;/code&gt; and &lt;code&gt;.descNullsFirst&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player ORDER BY score ASC NULLS LAST
Player.order(\.name.ascNullsLast)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Each &lt;code&gt;order&lt;/code&gt; call clears any previous ordering:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player ORDER BY name
Player.order(\.score).order(\.name)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/orderedrequest/reversed()&quot;&gt;&lt;code&gt;reversed()&lt;/code&gt;&lt;/a&gt; reverses the eventual orderings.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player ORDER BY score ASC, name DESC
Player.order { [$0.score.desc, $0.name] }.reversed()
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;If no ordering was already specified, this method has no effect:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player
Player.all().reversed()
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest/limit(_:offset:)&quot;&gt;&lt;code&gt;limit(limit, offset: offset)&lt;/code&gt;&lt;/a&gt; limits and pages results.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player LIMIT 5
Player.limit(5)

// SELECT * FROM player LIMIT 5 OFFSET 10
Player.limit(5, offset: 10)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/joining(required:)&quot;&gt;&lt;code&gt;joining(required:)&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/joining(optional:)&quot;&gt;&lt;code&gt;joining(optional:)&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/including(required:)&quot;&gt;&lt;code&gt;including(required:)&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/including(optional:)&quot;&gt;&lt;code&gt;including(optional:)&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/joinablerequest/including(all:)&quot;&gt;&lt;code&gt;including(all:)&lt;/code&gt;&lt;/a&gt; fetch and join records through &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations&lt;/a&gt;.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT player.*, team.*
// FROM player
// JOIN team ON team.id = player.teamId
Player.including(required: Player.team)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/derivablerequest/with(_:)&quot;&gt;&lt;code&gt;with(cte)&lt;/code&gt;&lt;/a&gt; embeds a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CommonTableExpressions.md&quot;&gt;common table expression&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// WITH ... SELECT * FROM player
let cte = CommonTableExpression(...)
Player.with(cte)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Other requests that involve the primary key:&lt;/p&gt; 
  &lt;ul&gt; 
   &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest/selectprimarykey(as:)&quot;&gt;&lt;code&gt;selectPrimaryKey(as:)&lt;/code&gt;&lt;/a&gt; selects the primary key.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT id FROM player
Player.selectPrimaryKey(as: Int64.self)    // QueryInterfaceRequest&amp;lt;Int64&amp;gt;

// SELECT code FROM country
Country.selectPrimaryKey(as: String.self)  // QueryInterfaceRequest&amp;lt;String&amp;gt;

// SELECT citizenId, countryCode FROM citizenship
Citizenship.selectPrimaryKey(as: Row.self) // QueryInterfaceRequest&amp;lt;Row&amp;gt;
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
   &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/orderbyprimarykey()&quot;&gt;&lt;code&gt;orderByPrimaryKey()&lt;/code&gt;&lt;/a&gt; sorts by primary key.&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player ORDER BY id
Player.orderByPrimaryKey()

// SELECT * FROM country ORDER BY code
Country.orderByPrimaryKey()

// SELECT * FROM citizenship ORDER BY citizenId, countryCode
Citizenship.orderByPrimaryKey()
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
   &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/tablerequest/groupbyprimarykey()&quot;&gt;&lt;code&gt;groupByPrimaryKey()&lt;/code&gt;&lt;/a&gt; groups rows by primary key.&lt;/p&gt; &lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;You can refine requests by chaining those methods:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE (email IS NOT NULL) ORDER BY name
Player.order(\.name).filter { $0.email != nil }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;order&lt;/code&gt;, &lt;code&gt;group&lt;/code&gt;, and &lt;code&gt;limit&lt;/code&gt; methods ignore and replace previously applied selection, orderings, grouping, and limits. On the opposite, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;matching&lt;/code&gt;, and &lt;code&gt;having&lt;/code&gt; methods extend the query:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Player                          // SELECT * FROM player
    .filter { $0.name != nil }  // WHERE (name IS NOT NULL)
    .filter { $0.email != nil } //        AND (email IS NOT NULL)
    .order(\.name)              // - ignored -
    .reversed()                 // - ignored -
    .order(\.score)             // ORDER BY score
    .limit(20, offset: 40)      // - ignored -
    .limit(10)                  // LIMIT 10
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Raw SQL snippets are also accepted, with eventual &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statementarguments&quot;&gt;arguments&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT DATE(creationDate), COUNT(*) FROM player WHERE name = &#39;Arthur&#39; GROUP BY date(creationDate)
Player
    .select(sql: &quot;DATE(creationDate), COUNT(*)&quot;)
    .filter(sql: &quot;name = ?&quot;, arguments: [&quot;Arthur&quot;])
    .group(sql: &quot;DATE(creationDate)&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Columns Selected by a Request&lt;/h3&gt; 
&lt;p&gt;By default, query interface requests select all columns:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player
struct Player: TableRecord { ... }
let request = Player.all()

// SELECT * FROM player
let table = Table(&quot;player&quot;)
let request = table.all()
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;The selection can be changed for each individual requests, or in the case of record-based requests, for all requests built from this record type.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;The &lt;code&gt;select(...)&lt;/code&gt; and &lt;code&gt;select(..., as:)&lt;/code&gt; methods change the selection of a single request (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-from-requests&quot;&gt;Fetching from Requests&lt;/a&gt; for detailed information):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.select { max($0.score) }
let maxScore = try Int.fetchOne(db, request) // Int?

let request = Player.select({ max($0.score) }, as: Int.self)
let maxScore = try request.fetchOne(db)      // Int?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The default selection for a record type is controlled by the &lt;code&gt;databaseSelection&lt;/code&gt; property. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Select a limited set of columns
struct RestrictedPlayer: TableRecord {
    static let databaseTableName = &quot;player&quot;
    
    enum Columns {
        static let id = Column(&quot;id&quot;)
        static let name = Column(&quot;name&quot;)
    }
    
    static var databaseSelection: [any SQLSelectable] {
        [Columns.id, Columns.name]
    }
}

// SELECT id, name FROM player
let request = RestrictedPlayer.all()
&lt;/code&gt;&lt;/pre&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Select all but a few columns
struct Player : TableRecord {
    static var databaseSelection: [any SQLSelectable] { 
        [.allColumns(excluding: [&quot;generatedColumn&quot;])]
    }
}

// SELECT id, name FROM player
let request = RestrictedPlayer.all()
&lt;/code&gt;&lt;/pre&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Select all columns and more
struct ExtendedPlayer : TableRecord {
    static let databaseTableName = &quot;player&quot;
    static var databaseSelection: [any SQLSelectable] {
        [.allColumns, .rowID]
    }
}

// SELECT *, rowid FROM player
let request = ExtendedPlayer.all()
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: make sure the &lt;code&gt;databaseSelection&lt;/code&gt; property is explicitly declared as &lt;code&gt;[any SQLSelectable]&lt;/code&gt;. If it is not, the Swift compiler may silently miss the protocol requirement, resulting in sticky &lt;code&gt;SELECT *&lt;/code&gt; requests. To verify your setup, see the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-print-a-request-as-sql&quot;&gt;How do I print a request as SQL?&lt;/a&gt; FAQ.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Expressions&lt;/h2&gt; 
&lt;p&gt;Feed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#requests&quot;&gt;requests&lt;/a&gt; with SQL expressions built from your Swift code:&lt;/p&gt; 
&lt;h3&gt;SQL Operators&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/sqlspecificexpressible&quot;&gt;&lt;code&gt;SQLSpecificExpressible&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;GRDB comes with a Swift version of many SQLite &lt;a href=&quot;https://sqlite.org/lang_expr.html#operators&quot;&gt;built-in operators&lt;/a&gt;, listed below. But not all: see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#embedding-sql-in-query-interface-requests&quot;&gt;Embedding SQL in Query Interface Requests&lt;/a&gt; for a way to add support for missing SQL operators.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;=&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;IS&lt;/code&gt;, &lt;code&gt;IS NOT&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Comparison operators are based on the Swift operators &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;===&lt;/code&gt;, &lt;code&gt;!==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE (name = &#39;Arthur&#39;)
Player.filter { $0.name == &quot;Arthur&quot; }

// SELECT * FROM player WHERE (name IS NULL)
Player.filter { $0.name == nil }

// SELECT * FROM player WHERE (score IS 1000)
Player.filter { $0.score === 1000 }

// SELECT * FROM rectangle WHERE width &amp;lt; height
Rectangle.filter { $0.width &amp;lt; $0.height }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Subqueries are supported:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE score = (SELECT max(score) FROM player)
let maximumScore = Player.select { max($0.score) }
Player.filter { $0.score == maximumScore }

// SELECT * FROM player WHERE score = (SELECT max(score) FROM player)
let maximumScore = SQLRequest(&quot;SELECT max(score) FROM player&quot;)
Player.filter { $0.score == maximumScore }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: SQLite string comparison, by default, is case-sensitive and not Unicode-aware. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#string-comparison&quot;&gt;string comparison&lt;/a&gt; if you need more control.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;&lt;/p&gt; &lt;p&gt;SQLite arithmetic operators are derived from their Swift equivalent:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT ((temperature * 1.8) + 32) AS fahrenheit FROM planet
Planet.select { ($0.temperature * 1.8 + 32).forKey(&quot;fahrenheit&quot;) }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: an expression like &lt;code&gt;nameColumn + &quot;rrr&quot;&lt;/code&gt; will be interpreted by SQLite as a numerical addition (with funny results), not as a string concatenation. See the &lt;code&gt;concat&lt;/code&gt; operator below.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;p&gt;When you want to join a sequence of expressions with the &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;*&lt;/code&gt; operator, use &lt;code&gt;joined(operator:)&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT score + bonus + 1000 FROM player
Player.select {
    [$0.score, $0.bonus, 1000.databaseValue].joined(operator: .add)
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Note in the example above how you concatenate raw values: &lt;code&gt;1000.databaseValue&lt;/code&gt;. A plain &lt;code&gt;1000&lt;/code&gt; would not compile.&lt;/p&gt; &lt;p&gt;When the sequence is empty, &lt;code&gt;joined(operator: .add)&lt;/code&gt; returns 0, and &lt;code&gt;joined(operator: .multiply)&lt;/code&gt; returns 1.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Bitwise operations (bitwise and, or, not, left shift, right shift) are derived from their Swift equivalent:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT mask &amp;amp; 2 AS isRocky FROM planet
Planet.select { ($0.mask &amp;amp; 2).forKey(&quot;isRocky&quot;) }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;||&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Concatenate several strings:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT firstName || &#39; &#39; || lastName FROM player
Player.select {
    [$0.firstName, &quot; &quot;.databaseValue, $0.lastName].joined(operator: .concat)
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Note in the example above how you concatenate raw strings: &lt;code&gt;&quot; &quot;.databaseValue&lt;/code&gt;. A plain &lt;code&gt;&quot; &quot;&lt;/code&gt; would not compile.&lt;/p&gt; &lt;p&gt;When the sequence is empty, &lt;code&gt;joined(operator: .concat)&lt;/code&gt; returns the empty string.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;AND&lt;/code&gt;, &lt;code&gt;OR&lt;/code&gt;, &lt;code&gt;NOT&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The SQL logical operators are derived from the Swift &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt; and &lt;code&gt;!&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE ((NOT isVerified) OR (score &amp;lt; 1000))
Player.filter { !$0.isVerified || $0.score &amp;lt; 1000 }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When you want to join a sequence of expressions with the &lt;code&gt;AND&lt;/code&gt; or &lt;code&gt;OR&lt;/code&gt; operator, use &lt;code&gt;joined(operator:)&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE (isVerified AND (score &amp;gt;= 1000) AND (name IS NOT NULL))
Player.filter {
    [$0.isVerified, $0.score &amp;gt;= 1000, $0.name != nil].joined(operator: .and)
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When the sequence is empty, &lt;code&gt;joined(operator: .and)&lt;/code&gt; returns true, and &lt;code&gt;joined(operator: .or)&lt;/code&gt; returns false:&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;NOT IN&lt;/code&gt;&lt;/p&gt; &lt;p&gt;To check inclusion in a Swift sequence (array, set, range…), call the &lt;code&gt;contains&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE id IN (1, 2, 3)
Player.filter { [1, 2, 3].contains($0.id) }

// SELECT * FROM player WHERE id NOT IN (1, 2, 3)
Player.filter { ![1, 2, 3].contains($0.id) }

// SELECT * FROM player WHERE score BETWEEN 0 AND 1000
Player.filter { (0...1000).contains($0.score) }

// SELECT * FROM player WHERE (score &amp;gt;= 0) AND (score &amp;lt; 1000)
Player.filter { (0..&amp;lt;1000).contains($0.score) }

// SELECT * FROM player WHERE initial BETWEEN &#39;A&#39; AND &#39;N&#39;
Player.filter { (&quot;A&quot;...&quot;N&quot;).contains($0.initial) }

// SELECT * FROM player WHERE (initial &amp;gt;= &#39;A&#39;) AND (initial &amp;lt; &#39;N&#39;)
Player.filter { (&quot;A&quot;..&amp;lt;&quot;N&quot;).contains($0.initial) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;To check inclusion inside a subquery, call the &lt;code&gt;contains&lt;/code&gt; method as well:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE id IN (SELECT playerId FROM playerSelection)
let selectedPlayerIds = PlayerSelection.select(\.playerId)
Player.filter { selectedPlayerIds.contains($0.id) }

// SELECT * FROM player WHERE id IN (SELECT playerId FROM playerSelection)
let selectedPlayerIds = SQLRequest(&quot;SELECT playerId FROM playerSelection&quot;)
Player.filter { selectedPlayerIds.contains($0.id) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;To check inclusion inside a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CommonTableExpressions.md&quot;&gt;common table expression&lt;/a&gt;, call the &lt;code&gt;contains&lt;/code&gt; method as well:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// WITH selectedName AS (...)
// SELECT * FROM player WHERE name IN selectedName
let cte = CommonTableExpression(named: &quot;selectedName&quot;, ...)
Player
    .with(cte)
    .filter { cte.contains($0.name) }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: SQLite string comparison, by default, is case-sensitive and not Unicode-aware. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#string-comparison&quot;&gt;string comparison&lt;/a&gt; if you need more control.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;EXISTS&lt;/code&gt;, &lt;code&gt;NOT EXISTS&lt;/code&gt;&lt;/p&gt; &lt;p&gt;To check if a subquery would return rows, call the &lt;code&gt;exists&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Teams that have at least one other player
//
//  SELECT * FROM team
//  WHERE EXISTS (SELECT * FROM player WHERE teamId = team.id)
let teamAlias = TableAlias&amp;lt;Team&amp;gt;()
let player = Player.filter { $0.teamId == teamAlias.id }
let teams = Team.aliased(teamAlias).filter(player.exists())

// Teams that have no player
//
//  SELECT * FROM team
//  WHERE NOT EXISTS (SELECT * FROM player WHERE teamId = team.id)
let teams = Team.aliased(teamAlias).filter(!player.exists())
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;In the above example, you use a &lt;code&gt;TableAlias&lt;/code&gt; in order to let a subquery refer to a column from another table.&lt;/p&gt; &lt;p&gt;In the next example, which involves the same table twice, the table alias requires an explicit disambiguation with &lt;code&gt;TableAlias(name:)&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Players who coach at least one other player
//
//  SELECT coach.* FROM player coach
//  WHERE EXISTS (SELECT * FROM player WHERE coachId = coach.id)
let coachAlias = TableAlias&amp;lt;Player&amp;gt;(name: &quot;coach&quot;)
let coachedPlayer = Player.filter { $0.coachId == coachAlias.id }
let coaches = Player.aliased(coachAlias).filter(coachedPlayer.exists())
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Finally, subqueries can also be expressed as SQL, with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT coach.* FROM player coach
// WHERE EXISTS (SELECT * FROM player WHERE coachId = coach.id)
let coachedPlayer = SQLRequest(&quot;SELECT * FROM player WHERE coachId = \(coachAlias.id)&quot;)
let coaches = Player.aliased(coachAlias).filter(coachedPlayer.exists())
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;LIKE&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The SQLite LIKE operator is available as the &lt;code&gt;like&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE (email LIKE &#39;%@example.com&#39;)
Player.filter { $0.email.like(&quot;%@example.com&quot;) }

// SELECT * FROM book WHERE (title LIKE &#39;%10\%%&#39; ESCAPE &#39;\&#39;)
Player.filter { $0.email.like(&quot;%10\\%%&quot;, escape: &quot;\\&quot;) }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: the SQLite LIKE operator is case-insensitive but not Unicode-aware. For example, the expression &lt;code&gt;&#39;a&#39; LIKE &#39;A&#39;&lt;/code&gt; is true but &lt;code&gt;&#39;æ&#39; LIKE &#39;Æ&#39;&lt;/code&gt; is false.&lt;/p&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;MATCH&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The full-text MATCH operator is available through &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md#fts3pattern&quot;&gt;FTS3Pattern&lt;/a&gt; (for FTS3 and FTS4 tables) and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md#fts5pattern&quot;&gt;FTS5Pattern&lt;/a&gt; (for FTS5):&lt;/p&gt; &lt;p&gt;FTS3 and FTS4:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let pattern = FTS3Pattern(matchingAllTokensIn: &quot;SQLite database&quot;)

// SELECT * FROM document WHERE document MATCH &#39;sqlite database&#39;
Document.matching(pattern)

// SELECT * FROM document WHERE content MATCH &#39;sqlite database&#39;
Document.filter { $0.content.match(pattern) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;FTS5:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let pattern = FTS5Pattern(matchingAllTokensIn: &quot;SQLite database&quot;)

// SELECT * FROM document WHERE document MATCH &#39;sqlite database&#39;
Document.matching(pattern)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;AS&lt;/code&gt;&lt;/p&gt; &lt;p&gt;To give an alias to an expression, use the &lt;code&gt;forKey&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT (score + bonus) AS total
// FROM player
Player.select { ($0.score + $0.bonus).forKey(&quot;total&quot;) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;If you need to refer to this aliased column in another place of the request, use a detached column:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT (score + bonus) AS total
// FROM player 
// ORDER BY total
Player
    .select { ($0.score + $0.bonus).forKey(&quot;total&quot;) }
    .order(Column(&quot;total&quot;).detached)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The detached column &lt;code&gt;Column(&quot;total&quot;).detached&lt;/code&gt; is not considered as a part of the &quot;player&quot; table, so it is always rendered as &lt;code&gt;total&lt;/code&gt; in the generated SQL, even when the request involves other tables via an &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;association&lt;/a&gt; or a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CommonTableExpressions.md&quot;&gt;common table expression&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;SQL Functions&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/sqlspecificexpressible&quot;&gt;&lt;code&gt;SQLSpecificExpressible&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;GRDB comes with a Swift version of many SQLite &lt;a href=&quot;https://sqlite.org/lang_corefunc.html&quot;&gt;built-in functions&lt;/a&gt;, listed below. But not all: see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#embedding-sql-in-query-interface-requests&quot;&gt;Embedding SQL in Query Interface Requests&lt;/a&gt; for a way to add support for missing SQL functions.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;ABS&lt;/code&gt;, &lt;code&gt;AVG&lt;/code&gt;, &lt;code&gt;COALESCE&lt;/code&gt;, &lt;code&gt;COUNT&lt;/code&gt;, &lt;code&gt;DATETIME&lt;/code&gt;, &lt;code&gt;JULIANDAY&lt;/code&gt;, &lt;code&gt;LENGTH&lt;/code&gt;, &lt;code&gt;MAX&lt;/code&gt;, &lt;code&gt;MIN&lt;/code&gt;, &lt;code&gt;SUM&lt;/code&gt;, &lt;code&gt;TOTAL&lt;/code&gt;:&lt;/p&gt; &lt;p&gt;Those are based on the &lt;code&gt;abs&lt;/code&gt;, &lt;code&gt;average&lt;/code&gt;, &lt;code&gt;coalesce&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;dateTime&lt;/code&gt;, &lt;code&gt;julianDay&lt;/code&gt;, &lt;code&gt;length&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt;, and &lt;code&gt;total&lt;/code&gt; Swift functions:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT MIN(score), MAX(score) FROM player
Player.select { [min($0.score), max($0.score)] }

// SELECT COUNT(name) FROM player
Player.select { count($0.name) }

// SELECT COUNT(DISTINCT name) FROM player
Player.select { count(distinct: $0.name) }

// SELECT JULIANDAY(date, &#39;start of year&#39;) FROM game
Game.select { julianDay($0.date, .startOfYear) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;For more information about the functions &lt;code&gt;dateTime&lt;/code&gt; and &lt;code&gt;julianDay&lt;/code&gt;, see &lt;a href=&quot;https://www.sqlite.org/lang_datefunc.html&quot;&gt;Date And Time Functions&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;CAST&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Use the &lt;code&gt;cast&lt;/code&gt; Swift function:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT (CAST(wins AS REAL) / games) AS successRate FROM player
Player.select { (cast($0.wins, as: .real) / $0.games).forKey(&quot;successRate&quot;) }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;See &lt;a href=&quot;https://www.sqlite.org/lang_expr.html#castexpr&quot;&gt;CAST expressions&lt;/a&gt; for more information about SQLite conversions.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;IFNULL&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Use the Swift &lt;code&gt;??&lt;/code&gt; operator:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT IFNULL(name, &#39;Anonymous&#39;) FROM player
Player.select { $0.name ?? &quot;Anonymous&quot; }

// SELECT IFNULL(name, email) FROM player
Player.select { $0.name ?? $0.email }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;LOWER&lt;/code&gt;, &lt;code&gt;UPPER&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The query interface does not give access to those SQLite functions. Nothing against them, but they are not unicode aware.&lt;/p&gt; &lt;p&gt;Instead, GRDB extends SQLite with SQL functions that call the Swift built-in string functions &lt;code&gt;capitalized&lt;/code&gt;, &lt;code&gt;lowercased&lt;/code&gt;, &lt;code&gt;uppercased&lt;/code&gt;, &lt;code&gt;localizedCapitalized&lt;/code&gt;, &lt;code&gt;localizedLowercased&lt;/code&gt; and &lt;code&gt;localizedUppercased&lt;/code&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Player.select { $0.name.uppercased() }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;blockquote&gt; 
   &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: When &lt;em&gt;comparing&lt;/em&gt; strings, you&#39;d rather use a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#string-comparison&quot;&gt;collation&lt;/a&gt;:&lt;/p&gt; 
   &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String = ...

// Not recommended
Player.filter { $0.name.uppercased() == name.uppercased() }

// Better
Player.filter { $0.name.collating(.caseInsensitiveCompare) == name }
&lt;/code&gt;&lt;/pre&gt; 
  &lt;/blockquote&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Custom SQL functions and aggregates&lt;/p&gt; &lt;p&gt;You can apply your own &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-functions-&quot;&gt;custom SQL functions and aggregates&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let myFunction = DatabaseFunction(&quot;myFunction&quot;, ...)

// SELECT myFunction(name) FROM player
Player.select { myFunction($0.name) }
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Embedding SQL in Query Interface Requests&lt;/h2&gt; 
&lt;p&gt;You will sometimes want to extend your query interface requests with SQL snippets. This can happen because GRDB does not provide a Swift interface for some SQL function or operator, or because you want to use an SQLite construct that GRDB does not support.&lt;/p&gt; 
&lt;p&gt;Support for extensibility is large, but not unlimited. All the SQL queries built by the query interface request have the shape below. &lt;em&gt;If you need something else, you&#39;ll have to use &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-api&quot;&gt;raw SQL requests&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;WITH ...     -- 1
SELECT ...   -- 2
FROM ...     -- 3
JOIN ...     -- 4
WHERE ...    -- 5
GROUP BY ... -- 6
HAVING ...   -- 7
ORDER BY ... -- 8
LIMIT ...    -- 9
&lt;/code&gt;&lt;/pre&gt; 
&lt;ol&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;WITH ...&lt;/code&gt;: see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/CommonTableExpressions.md&quot;&gt;Common Table Expressions&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;SELECT ...&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The selection can be provided as raw SQL:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT IFNULL(name, &#39;O&#39;&#39;Brien&#39;), score FROM player
let request = Player.select(sql: &quot;IFNULL(name, &#39;O&#39;&#39;Brien&#39;), score&quot;)

// SELECT IFNULL(name, &#39;O&#39;&#39;Brien&#39;), score FROM player
let defaultName = &quot;O&#39;Brien&quot;
let request = Player.select(sql: &quot;IFNULL(name, ?), score&quot;, arguments: [suffix])
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The selection can be provided with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT IFNULL(name, &#39;O&#39;&#39;Brien&#39;), score FROM player
let defaultName = &quot;O&#39;Brien&quot;
let request = Player.select(literal: &quot;IFNULL(name, \(defaultName)), score&quot;)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The selection can be provided with a mix of Swift and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT IFNULL(name, &#39;O&#39;&#39;Brien&#39;) AS displayName, score FROM player
let defaultName = &quot;O&#39;Brien&quot;
let request = Player.select {
    let displayName: SQL = &quot;IFNULL(\($0.name), \(defaultName)) AS displayName&quot;
    return [displayName, $0.score]
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When the custom SQL snippet should behave as a full-fledged expression, with support for the &lt;code&gt;+&lt;/code&gt; Swift operator, the &lt;code&gt;forKey&lt;/code&gt; aliasing method, and all other &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sql-operators&quot;&gt;SQL Operators&lt;/a&gt;, build an &lt;em&gt;expression literal&lt;/em&gt; with the &lt;code&gt;SQL.sqlExpression&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT IFNULL(name, &#39;O&#39;&#39;Brien&#39;) AS displayName, score FROM player
let defaultName = &quot;O&#39;Brien&quot;
let request = Player.select {
    let displayName = SQL(&quot;IFNULL(\($0.name), \(defaultName))&quot;).sqlExpression
    return [displayName.forKey(&quot;displayName&quot;), $0.score]
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Such expression literals allow you to build a reusable support library of SQL functions or operators that are missing from the query interface. For example, you can define a Swift &lt;code&gt;date&lt;/code&gt; function:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;func date(_ value: some SQLSpecificExpressible) -&amp;gt; SQLExpression {
    SQL(&quot;DATE(\(value))&quot;).sqlExpression
}

// SELECT * FROM &quot;player&quot; WHERE DATE(&quot;createdAt&quot;) = &#39;2020-01-23&#39;
let request = Player.filter { date($0.createdAt) == &quot;2020-01-23&quot; }
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;See the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/QueryInterfaceOrganization.md&quot;&gt;Query Interface Organization&lt;/a&gt; for more information about &lt;code&gt;SQLSpecificExpressible&lt;/code&gt; and &lt;code&gt;SQLExpression&lt;/code&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;FROM ...&lt;/code&gt;: only one table is supported here. You can not customize this SQL part.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;JOIN ...&lt;/code&gt;: joins are fully controlled by &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations&lt;/a&gt;. You can not customize this SQL part.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;WHERE ...&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The WHERE clause can be provided as raw SQL:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE score &amp;gt;= 1000
let request = Player.filter(sql: &quot;score &amp;gt;= 1000&quot;)

// SELECT * FROM player WHERE score &amp;gt;= 1000
let minScore = 1000
let request = Player.filter(sql: &quot;score &amp;gt;= ?&quot;, arguments: [minScore])
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The WHERE clause can be provided with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE score &amp;gt;= 1000
let minScore = 1000
let request = Player.filter(literal: &quot;score &amp;gt;= \(minScore)&quot;)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The WHERE clause can be provided with a mix of Swift and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM player WHERE (score &amp;gt;= 1000) AND (team = &#39;red&#39;)
let minScore = 1000
let request = Player.filter { 
    let scoreCondition: SQL = &quot;\($0.score) &amp;gt;= \(minScore)&quot;
    return scoreCondition &amp;amp;&amp;amp; $0.team == &quot;red&quot;
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;See &lt;code&gt;SELECT ...&lt;/code&gt; above for more SQL Interpolation examples.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;GROUP BY ...&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The GROUP BY clause can be provided as raw SQL, SQL Interpolation, or a mix of Swift and SQL Interpolation, just as the selection and the WHERE clause (see above).&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;HAVING ...&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The HAVING clause can be provided as raw SQL, SQL Interpolation, or a mix of Swift and SQL Interpolation, just as the selection and the WHERE clause (see above).&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;ORDER BY ...&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The ORDER BY clause can be provided as raw SQL, SQL Interpolation, or a mix of Swift and SQL Interpolation, just as the selection and the WHERE clause (see above).&lt;/p&gt; &lt;p&gt;In order to support the &lt;code&gt;desc&lt;/code&gt; and &lt;code&gt;asc&lt;/code&gt; query interface operators, and the &lt;code&gt;reversed()&lt;/code&gt; query interface method, you must provide your orderings as &lt;em&gt;expression literals&lt;/em&gt; with the &lt;code&gt;SQL.sqlExpression&lt;/code&gt; method:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM &quot;player&quot; 
// ORDER BY (score + bonus) ASC, name DESC
let request = Player
    .order {
        let total = SQL(&quot;(\($0.score) + \($0.bonus))&quot;).sqlExpression
        return [total.desc, $0.name]
    }
    .reversed()
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;code&gt;LIMIT ...&lt;/code&gt;: use the &lt;code&gt;limit(_:offset:)&lt;/code&gt; method. You can not customize this SQL part.&lt;/p&gt; &lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2&gt;Fetching from Requests&lt;/h2&gt; 
&lt;p&gt;Once you have a request, you can fetch the records at the origin of the request:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Some request based on `Player`
let request = Player.filter { ... }... // QueryInterfaceRequest&amp;lt;Player&amp;gt;

// Fetch players:
try request.fetchCursor(db) // A Cursor of Player
try request.fetchAll(db)    // [Player]
try request.fetchSet(db)    // Set&amp;lt;Player&amp;gt;
try request.fetchOne(db)    // Player?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let allPlayers = try Player.fetchAll(db)                            // [Player]
let arthur = try Player.filter { $0.name == &quot;Arthur&quot; }.fetchOne(db) // Player?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetching-methods&quot;&gt;fetching methods&lt;/a&gt; for information about the &lt;code&gt;fetchCursor&lt;/code&gt;, &lt;code&gt;fetchAll&lt;/code&gt;, &lt;code&gt;fetchSet&lt;/code&gt; and &lt;code&gt;fetchOne&lt;/code&gt; methods.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;You sometimes want to fetch other values&lt;/strong&gt;.&lt;/p&gt; 
&lt;p&gt;The simplest way is to use the request as an argument to a fetching method of the desired type:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Fetch an Int
let request = Player.select { max($0.score) }
let maxScore = try Int.fetchOne(db, request) // Int?

// Fetch a Row
let request = Player.select { [min($0.score), max($0.score)] }
let row = try Row.fetchOne(db, request)!     // Row
let minScore = row[0] as Int?
let maxScore = row[1] as Int?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also change the request so that it knows the type it has to fetch:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;With &lt;code&gt;asRequest(of:)&lt;/code&gt;, useful when you use &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct BookInfo: FetchableRecord, Decodable {
    var book: Book
    var author: Author
}

// A request of BookInfo
let request = Book
    .including(required: Book.author)
    .asRequest(of: BookInfo.self)

let bookInfos = try dbQueue.read { db in
    try request.fetchAll(db) // [BookInfo]
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;With &lt;code&gt;select(..., as:)&lt;/code&gt;, which is handy when you change the selection:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// A request of Int
let request = Player.select({ max($0.score) }, as: Int.self)

let maxScore = try dbQueue.read { db in
    try request.fetchOne(db) // Int?
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Fetching by Key&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Fetching records according to their primary key&lt;/strong&gt; is a common task.&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt; can use the type-safe methods &lt;code&gt;find(_&lt;span&gt;🆔&lt;/span&gt;)&lt;/code&gt;, &lt;code&gt;fetchOne(_&lt;span&gt;🆔&lt;/span&gt;)&lt;/code&gt;, &lt;code&gt;fetchAll(_:ids:)&lt;/code&gt; and &lt;code&gt;fetchSet(_:ids:)&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.find(db, id: 1)                   // Player
try Player.fetchOne(db, id: 1)               // Player?
try Country.fetchAll(db, ids: [&quot;FR&quot;, &quot;US&quot;])  // [Countries]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;All record types can use &lt;code&gt;find(_&lt;span&gt;🔑&lt;/span&gt;)&lt;/code&gt;, &lt;code&gt;fetchOne(_&lt;span&gt;🔑&lt;/span&gt;)&lt;/code&gt;, &lt;code&gt;fetchAll(_:keys:)&lt;/code&gt; and &lt;code&gt;fetchSet(_:keys:)&lt;/code&gt; that apply conditions on primary and unique keys:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.find(db, key: 1)                  // Player
try Player.fetchOne(db, key: 1)              // Player?
try Country.fetchAll(db, keys: [&quot;FR&quot;, &quot;US&quot;]) // [Country]
try Player.fetchOne(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])            // Player?
try Citizenship.fetchOne(db, key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;]) // Citizenship?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When the table has no explicit primary key, GRDB uses the &lt;a href=&quot;https://www.sqlite.org/rowidtable.html&quot;&gt;hidden &lt;code&gt;rowid&lt;/code&gt; column&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT * FROM document WHERE rowid = 1
try Document.fetchOne(db, key: 1)            // Document?
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;When you want to build a request and plan to fetch from it later&lt;/strong&gt;, use a &lt;code&gt;filter&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.filter(id: 1)
let request = Country.filter(ids: [&quot;FR&quot;, &quot;US&quot;])
let request = Player.filter(key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
let request = Citizenship.filter(key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;])
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Testing for Record Existence&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;You can check if a request has matching rows in the database.&lt;/strong&gt;&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Some request based on `Player`
let request = Player.filter { ... }...

// Check for player existence:
let noSuchPlayer = try request.isEmpty(db) // Bool
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You should check for emptiness instead of counting:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Correct
let noSuchPlayer = try request.fetchCount(db) == 0
// Even better
let noSuchPlayer = try request.isEmpty(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;You can also check if a given primary or unique key exists in the database.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt; can use the type-safe method &lt;code&gt;exists(_&lt;span&gt;🆔&lt;/span&gt;)&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.exists(db, id: 1)
try Country.exists(db, id: &quot;FR&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;All record types can use &lt;code&gt;exists(_&lt;span&gt;🔑&lt;/span&gt;)&lt;/code&gt; that can check primary and unique keys:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.exists(db, key: 1)
try Country.exists(db, key: &quot;FR&quot;)
try Player.exists(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
try Citizenship.exists(db, key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;])
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You should check for key existence instead of fetching a record and checking for nil:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Correct
let playerExists = try Player.fetchOne(db, id: 1) != nil
// Even better
let playerExists = try Player.exists(db, id: 1)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Fetching Aggregated Values&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Requests can count.&lt;/strong&gt; The &lt;code&gt;fetchCount()&lt;/code&gt; method returns the number of rows that would be returned by a fetch request:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// SELECT COUNT(*) FROM player
let count = try Player.fetchCount(db) // Int

// SELECT COUNT(*) FROM player WHERE email IS NOT NULL
let count = try Player.filter { $0.email != nil }.fetchCount(db)

// SELECT COUNT(DISTINCT name) FROM player
let count = try Player.select(\.name).distinct().fetchCount(db)

// SELECT COUNT(*) FROM (SELECT DISTINCT name, score FROM player)
let count = try Player.select { [$0.name, $0.score] }.distinct().fetchCount(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;Other aggregated values&lt;/strong&gt; can also be selected and fetched (see &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sql-functions&quot;&gt;SQL Functions&lt;/a&gt;):&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.select { max($0.score) }
let maxScore = try Int.fetchOne(db, request) // Int?

let request = Player.select { [min($0.score), max($0.score)] }
let row = try Row.fetchOne(db, request)!     // Row
let minScore = row[0] as Int?
let maxScore = row[1] as Int?
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Delete Requests&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Requests can delete records&lt;/strong&gt;, with the &lt;code&gt;deleteAll()&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// DELETE FROM player
try Player.deleteAll(db)

// DELETE FROM player WHERE team = &#39;Reds&#39;
try Player
    .filter { $0.team == &quot;Reds&quot; }
    .deleteAll(db)

// DELETE FROM player ORDER BY score LIMIT 10
try Player
    .order(\.score)
    .limit(10)
    .deleteAll(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; Deletion methods are available on types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol, and &lt;code&gt;Table&lt;/code&gt;:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: TableRecord { ... }
try Player.deleteAll(db)          // Fine
try Table(&quot;player&quot;).deleteAll(db) // Just as fine
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;&lt;strong&gt;Deleting records according to their primary key&lt;/strong&gt; is a common task.&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#identifiable-records&quot;&gt;Identifiable Records&lt;/a&gt; can use the type-safe methods &lt;code&gt;deleteOne(_&lt;span&gt;🆔&lt;/span&gt;)&lt;/code&gt; and &lt;code&gt;deleteAll(_:ids:)&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.deleteOne(db, id: 1)
try Country.deleteAll(db, ids: [&quot;FR&quot;, &quot;US&quot;])
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;All record types can use &lt;code&gt;deleteOne(_&lt;span&gt;🔑&lt;/span&gt;)&lt;/code&gt; and &lt;code&gt;deleteAll(_:keys:)&lt;/code&gt; that apply conditions on primary and unique keys:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.deleteOne(db, key: 1)
try Country.deleteAll(db, keys: [&quot;FR&quot;, &quot;US&quot;])
try Player.deleteOne(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
try Citizenship.deleteOne(db, key: [&quot;citizenId&quot;: 1, &quot;countryCode&quot;: &quot;FR&quot;])
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When the table has no explicit primary key, GRDB uses the &lt;a href=&quot;https://www.sqlite.org/rowidtable.html&quot;&gt;hidden &lt;code&gt;rowid&lt;/code&gt; column&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// DELETE FROM document WHERE rowid = 1
try Document.deleteOne(db, id: 1)             // Document?
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Update Requests&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Requests can batch update records&lt;/strong&gt;. The &lt;code&gt;updateAll()&lt;/code&gt; method accepts &lt;em&gt;column assignments&lt;/em&gt; defined with the &lt;code&gt;set(to:)&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// UPDATE player SET score = 0, isHealthy = 1, bonus = NULL
try Player.updateAll(db) { [
    $0.score.set(to: 0), 
    $0.isHealthy.set(to: true), 
    $0.bonus.set(to: nil),
] }

// UPDATE player SET score = 0 WHERE team = &#39;Reds&#39;
try Player
    .filter { $0.team == &quot;Reds&quot; }
    .updateAll(db) { $0.score.set(to: 0) }

// UPDATE player SET isGreat = 1 ORDER BY score DESC LIMIT 10
try Player
    .order(\.score.desc)
    .limit(10)
    .updateAll(db) { $0.isGreat.set(to: true) }

// UPDATE country SET population = 67848156 WHERE id = &#39;FR&#39;
try Country
    .filter(id: &quot;FR&quot;)
    .updateAll(db) { $0.population.set(to: 67_848_156) }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Column assignments accept any expression:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// UPDATE player SET score = score + (bonus * 2)
try Player.updateAll(db) {
    $0.score.set(to: $0.score + $0.bonus * 2)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;As a convenience, you can also use the &lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;*=&lt;/code&gt;, or &lt;code&gt;/=&lt;/code&gt; operators:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// UPDATE player SET score = score + (bonus * 2)
try Player.updateAll(db) { $0.score += $0.bonus * 2 }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Default &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#conflict-resolution&quot;&gt;Conflict Resolution&lt;/a&gt; rules apply, and you may also provide a specific one:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// UPDATE OR IGNORE player SET ...
try Player.updateAll(db, onConflict: .ignore) { /* assignments... */ }
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; The &lt;code&gt;updateAll&lt;/code&gt; method is available on types that adopt the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol, and &lt;code&gt;Table&lt;/code&gt;:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Player: TableRecord { ... }
try Player.updateAll(db, ...)          // Fine
try Table(&quot;player&quot;).updateAll(db, ...) // Just as fine
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Custom Requests&lt;/h2&gt; 
&lt;p&gt;Until now, we have seen &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#requests&quot;&gt;requests&lt;/a&gt; created from any type that adopts the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; protocol:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let request = Player.all()  // QueryInterfaceRequest&amp;lt;Player&amp;gt;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Those requests of type &lt;code&gt;QueryInterfaceRequest&lt;/code&gt; can fetch and count:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try request.fetchCursor(db) // A Cursor of Player
try request.fetchAll(db)    // [Player]
try request.fetchSet(db)    // Set&amp;lt;Player&amp;gt;
try request.fetchOne(db)    // Player?
try request.fetchCount(db)  // Int
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;When the query interface can not generate the SQL you need&lt;/strong&gt;, you can still fallback to &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetch-queries&quot;&gt;raw SQL&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Custom SQL is always welcome
try Player.fetchAll(db, sql: &quot;SELECT ...&quot;)   // [Player]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;But you may prefer to bring some elegance back in, and build custom requests:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// No custom SQL in sight
try Player.customRequest().fetchAll(db) // [Player]
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;To build custom requests&lt;/strong&gt;, you can use one of the built-in requests or derive requests from other requests.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/sqlrequest&quot;&gt;SQLRequest&lt;/a&gt; is a fetch request built from raw SQL. For example:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Player {
    static func filter(color: Color) -&amp;gt; SQLRequest&amp;lt;Player&amp;gt; {
        SQLRequest&amp;lt;Player&amp;gt;(
            sql: &quot;SELECT * FROM player WHERE color = ?&quot;
            arguments: [color])
    }
}

// [Player]
try Player.filter(color: .red).fetchAll(db)
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;SQLRequest supports &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/SQLInterpolation.md&quot;&gt;SQL Interpolation&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Player {
    static func filter(color: Color) -&amp;gt; SQLRequest&amp;lt;Player&amp;gt; {
        &quot;SELECT * FROM player WHERE color = \(color)&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;The &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterfacerequest/asrequest(of:)&quot;&gt;&lt;code&gt;asRequest(of:)&lt;/code&gt;&lt;/a&gt; method changes the type fetched by the request. It is useful, for example, when you use &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/AssociationsBasics.md&quot;&gt;Associations&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct BookInfo: FetchableRecord, Decodable {
    var book: Book
    var author: Author
}

let request = Book
    .including(required: Book.author)
    .asRequest(of: BookInfo.self)

// [BookInfo]
try request.fetchAll(db)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;The &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/fetchrequest/adapted(_:)&quot;&gt;&lt;code&gt;adapted(_:)&lt;/code&gt;&lt;/a&gt; method eases the consumption of complex rows with row adapters. See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/rowadapter&quot;&gt;&lt;code&gt;RowAdapter&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/splittingrowadapters(columncounts:)&quot;&gt;&lt;code&gt;splittingRowAdapters(columnCounts:)&lt;/code&gt;&lt;/a&gt; for a sample code that uses &lt;code&gt;adapted(_:)&lt;/code&gt;.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h1&gt;Encryption&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;GRDB can encrypt your database with &lt;a href=&quot;http://sqlcipher.net&quot;&gt;SQLCipher&lt;/a&gt; v3.4+.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;To use SQLCipher with the &lt;a href=&quot;https://swift.org/package-manager/&quot;&gt;Swift Package Manager&lt;/a&gt;, you must fork GRDB, and modify &lt;code&gt;Package.swift&lt;/code&gt;. Instructions are in the file itself, in comments that contain &quot;GRDB+SQLCipher&quot;.&lt;/p&gt; 
&lt;p&gt;To use SQLCipher with &lt;a href=&quot;http://cocoapods.org/&quot;&gt;CocoaPods&lt;/a&gt;, specify in your &lt;code&gt;Podfile&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# GRDB with SQLCipher 4
pod &#39;GRDB.swift/SQLCipher&#39;
pod &#39;SQLCipher&#39;, &#39;~&amp;gt; 4.0&#39;

# GRDB with SQLCipher 3
pod &#39;GRDB.swift/SQLCipher&#39;
pod &#39;SQLCipher&#39;, &#39;~&amp;gt; 3.4&#39;
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Make sure you remove any existing &lt;code&gt;pod &#39;GRDB.swift&#39;&lt;/code&gt; from your Podfile. &lt;code&gt;GRDB.swift/SQLCipher&lt;/code&gt; must be the only active GRDB pod in your whole project, or you will face linker or runtime errors, due to the conflicts between SQLCipher and the system SQLite.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#creating-or-opening-an-encrypted-database&quot;&gt;Creating or Opening an Encrypted Database&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#changing-the-passphrase-of-an-encrypted-database&quot;&gt;Changing the Passphrase of an Encrypted Database&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#exporting-a-database-to-an-encrypted-database&quot;&gt;Exporting a Database to an Encrypted Database&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#security-considerations&quot;&gt;Security Considerations&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Creating or Opening an Encrypted Database&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;You create and open an encrypted database&lt;/strong&gt; by providing a passphrase to your &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#database-connections&quot;&gt;database connection&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(&quot;secret&quot;)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;It is also in &lt;code&gt;prepareDatabase&lt;/code&gt; that you perform other &lt;a href=&quot;https://www.zetetic.net/sqlcipher/sqlcipher-api/&quot;&gt;SQLCipher configuration steps&lt;/a&gt; that must happen early in the lifetime of a SQLCipher connection. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(&quot;secret&quot;)
    try db.execute(sql: &quot;PRAGMA cipher_page_size = ...&quot;)
    try db.execute(sql: &quot;PRAGMA kdf_iter = ...&quot;)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When you want to open an existing SQLCipher 3 database with SQLCipher 4, you may want to run the &lt;code&gt;cipher_compatibility&lt;/code&gt; pragma:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Open an SQLCipher 3 database with SQLCipher 4
var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(&quot;secret&quot;)
    try db.execute(sql: &quot;PRAGMA cipher_compatibility = 3&quot;)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://www.zetetic.net/blog/2018/11/30/sqlcipher-400-release/&quot;&gt;SQLCipher 4.0.0 Release&lt;/a&gt; and &lt;a href=&quot;https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283&quot;&gt;Upgrading to SQLCipher 4&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;h3&gt;Changing the Passphrase of an Encrypted Database&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;You can change the passphrase&lt;/strong&gt; of an already encrypted database.&lt;/p&gt; 
&lt;p&gt;When you use a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasequeue&quot;&gt;database queue&lt;/a&gt;, open the database with the old passphrase, and then apply the new passphrase:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try db.changePassphrase(&quot;newSecret&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When you use a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;database pool&lt;/a&gt;, make sure that no concurrent read can happen by changing the passphrase within the &lt;code&gt;barrierWriteWithoutTransaction&lt;/code&gt; block. You must also ensure all future reads open a new database connection by calling the &lt;code&gt;invalidateReadOnlyConnections&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbPool.barrierWriteWithoutTransaction { db in
    try db.changePassphrase(&quot;newSecret&quot;)
    dbPool.invalidateReadOnlyConnections()
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: When an application wants to keep on using a database queue or pool after the passphrase has changed, it is responsible for providing the correct passphrase to the &lt;code&gt;usePassphrase&lt;/code&gt; method called in the database preparation function. Consider:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// WRONG: this won&#39;t work across a passphrase change
let passphrase = try getPassphrase()
var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(passphrase)
}

// CORRECT: get the latest passphrase when it is needed
var config = Configuration()
config.prepareDatabase { db in
    let passphrase = try getPassphrase()
    try db.usePassphrase(passphrase)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;/blockquote&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The &lt;code&gt;DatabasePool.barrierWriteWithoutTransaction&lt;/code&gt; method does not prevent &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasesnapshot&quot;&gt;database snapshots&lt;/a&gt; from accessing the database during the passphrase change, or after the new passphrase has been applied to the database. Those database accesses may throw errors. Applications should provide their own mechanism for invalidating open snapshots before the passphrase is changed.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Instead of changing the passphrase &quot;in place&quot; as described here, you can also export the database in a new encrypted database that uses the new passphrase. See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#exporting-a-database-to-an-encrypted-database&quot;&gt;Exporting a Database to an Encrypted Database&lt;/a&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;Exporting a Database to an Encrypted Database&lt;/h3&gt; 
&lt;p&gt;Providing a passphrase won&#39;t encrypt a clear-text database that already exists, though. SQLCipher can&#39;t do that, and you will get an error instead: &lt;code&gt;SQLite error 26: file is encrypted or is not a database&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;Instead, create a new encrypted database, at a distinct location, and export the content of the existing database. This can both encrypt a clear-text database, or change the passphrase of an encrypted database.&lt;/p&gt; 
&lt;p&gt;The technique to do that is &lt;a href=&quot;https://discuss.zetetic.net/t/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher-and-avoid-file-is-encrypted-or-is-not-a-database-errors/868/1&quot;&gt;documented&lt;/a&gt; by SQLCipher.&lt;/p&gt; 
&lt;p&gt;With GRDB, it gives:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// The existing database
let existingDBQueue = try DatabaseQueue(path: &quot;/path/to/existing.db&quot;)

// The new encrypted database, at some distinct location:
var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(&quot;secret&quot;)
}
let newDBQueue = try DatabaseQueue(path: &quot;/path/to/new.db&quot;, configuration: config)

try existingDBQueue.inDatabase { db in
    try db.execute(
        sql: &quot;&quot;&quot;
            ATTACH DATABASE ? AS encrypted KEY ?;
            SELECT sqlcipher_export(&#39;encrypted&#39;);
            DETACH DATABASE encrypted;
            &quot;&quot;&quot;,
        arguments: [newDBQueue.path, &quot;secret&quot;])
}

// Now the export is completed, and the existing database can be deleted.
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Security Considerations&lt;/h3&gt; 
&lt;h4&gt;Managing the lifetime of the passphrase string&lt;/h4&gt; 
&lt;p&gt;It is recommended to avoid keeping the passphrase in memory longer than necessary. To do this, make sure you load the passphrase from the &lt;code&gt;prepareDatabase&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// NOT RECOMMENDED: this keeps the passphrase in memory longer than necessary
let passphrase = try getPassphrase()
var config = Configuration()
config.prepareDatabase { db in
    try db.usePassphrase(passphrase)
}

// RECOMMENDED: only load the passphrase when it is needed
var config = Configuration()
config.prepareDatabase { db in
    let passphrase = try getPassphrase()
    try db.usePassphrase(passphrase)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This technique helps manages the lifetime of the passphrase, although keep in mind that the content of a String may remain intact in memory long after the object has been released.&lt;/p&gt; 
&lt;p&gt;For even better control over the lifetime of the passphrase in memory, use a Data object which natively provides the &lt;code&gt;resetBytes&lt;/code&gt; function.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// RECOMMENDED: only load the passphrase when it is needed and reset its content immediately after use
var config = Configuration()
config.prepareDatabase { db in
    var passphraseData = try getPassphraseData() // Data
    defer {
        passphraseData.resetBytes(in: 0..&amp;lt;passphraseData.count)
    }
    try db.usePassphrase(passphraseData)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Some demanding users will want to go further, and manage the lifetime of the raw passphrase bytes. See below.&lt;/p&gt; 
&lt;h4&gt;Managing the lifetime of the passphrase bytes&lt;/h4&gt; 
&lt;p&gt;GRDB offers convenience methods for providing the database passphrases as Swift strings: &lt;code&gt;usePassphrase(_:)&lt;/code&gt; and &lt;code&gt;changePassphrase(_:)&lt;/code&gt;. Those methods don&#39;t keep the passphrase String in memory longer than necessary. But they are as secure as the standard String type: the lifetime of actual passphrase bytes in memory is not under control.&lt;/p&gt; 
&lt;p&gt;When you want to precisely manage the passphrase bytes, talk directly to SQLCipher, using its raw C functions.&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    ... // Carefully load passphrase bytes
    let code = sqlite3_key(db.sqliteConnection, /* passphrase bytes */)
    ... // Carefully dispose passphrase bytes
    guard code == SQLITE_OK else {
        throw DatabaseError(
            resultCode: ResultCode(rawValue: code), 
            message: db.lastErrorMessage)
    }
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h4&gt;Passphrase availability vs. Database availability&lt;/h4&gt; 
&lt;p&gt;When the passphrase is securely stored in the system keychain, your application can protect it using the &lt;a href=&quot;https://developer.apple.com/documentation/security/ksecattraccessible&quot;&gt;&lt;code&gt;kSecAttrAccessible&lt;/code&gt;&lt;/a&gt; attribute.&lt;/p&gt; 
&lt;p&gt;Such protection prevents GRDB from creating SQLite connections when the passphrase is not available:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    let passphrase = try loadPassphraseFromSystemKeychain()
    try db.usePassphrase(passphrase)
}

// Success if and only if the passphrase is available
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For the same reason, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;database pools&lt;/a&gt;, which open SQLite connections on demand, may fail at any time as soon as the passphrase becomes unavailable:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Success if and only if the passphrase is available
let dbPool = try DatabasePool(path: dbPath, configuration: config)

// May fail if passphrase has turned unavailable
try dbPool.read { ... }

// May trigger value observation failure if passphrase has turned unavailable
try dbPool.write { ... }
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Because DatabasePool maintains a pool of long-lived SQLite connections, some database accesses will use an existing connection, and succeed. And some other database accesses will fail, as soon as the pool wants to open a new connection. It is impossible to predict which accesses will succeed or fail.&lt;/p&gt; 
&lt;p&gt;For the same reason, a database queue, which also maintains a long-lived SQLite connection, will remain available even after the passphrase has turned unavailable.&lt;/p&gt; 
&lt;p&gt;Applications are thus responsible for protecting database accesses when the passphrase is unavailable. To this end, they can use &lt;a href=&quot;https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files&quot;&gt;Data Protection&lt;/a&gt;. They can also destroy their instances of database queue or pool when the passphrase becomes unavailable.&lt;/p&gt; 
&lt;h2&gt;Backup&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;You can backup (copy) a database into another.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Backups can for example help you copying an in-memory database to and from a database file when you implement NSDocument subclasses.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let source: DatabaseQueue = ...      // or DatabasePool
let destination: DatabaseQueue = ... // or DatabasePool
try source.backup(to: destination)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The &lt;code&gt;backup&lt;/code&gt; method blocks the current thread until the destination database contains the same contents as the source database.&lt;/p&gt; 
&lt;p&gt;When the source is a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;database pool&lt;/a&gt;, concurrent writes can happen during the backup. Those writes may, or may not, be reflected in the backup, but they won&#39;t trigger any error.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;Database&lt;/code&gt; has an analogous &lt;code&gt;backup&lt;/code&gt; method.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let source: DatabaseQueue = ...      // or DatabasePool
let destination: DatabaseQueue = ... // or DatabasePool
try source.write { sourceDb in
    try destination.barrierWriteWithoutTransaction { destDb in
        try sourceDb.backup(to: destDb)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This method allows for the choice of source and destination &lt;code&gt;Database&lt;/code&gt; handles with which to backup the database.&lt;/p&gt; 
&lt;h3&gt;Backup Progress Reporting&lt;/h3&gt; 
&lt;p&gt;The &lt;code&gt;backup&lt;/code&gt; methods take optional &lt;code&gt;pagesPerStep&lt;/code&gt; and &lt;code&gt;progress&lt;/code&gt; parameters. Together these parameters can be used to track a database backup in progress and abort an incomplete backup.&lt;/p&gt; 
&lt;p&gt;When &lt;code&gt;pagesPerStep&lt;/code&gt; is provided, the database backup is performed in &lt;em&gt;steps&lt;/em&gt;. At each step, no more than &lt;code&gt;pagesPerStep&lt;/code&gt; database pages are copied from the source to the destination. The backup proceeds one step at a time until all pages have been copied.&lt;/p&gt; 
&lt;p&gt;When a &lt;code&gt;progress&lt;/code&gt; callback is provided, &lt;code&gt;progress&lt;/code&gt; is called after every backup step, including the last. Even if a non-default &lt;code&gt;pagesPerStep&lt;/code&gt; is specified or the backup is otherwise completed in a single step, the &lt;code&gt;progress&lt;/code&gt; callback will be called.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try source.backup(
    to: destination,
    pagesPerStep: ...)
    { backupProgress in
       print(&quot;Database backup progress:&quot;, backupProgress)
    }
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Aborting an Incomplete Backup&lt;/h3&gt; 
&lt;p&gt;If a call to &lt;code&gt;progress&lt;/code&gt; throws when &lt;code&gt;backupProgress.isComplete == false&lt;/code&gt;, the backup will be aborted and the error rethrown. However, if a call to &lt;code&gt;progress&lt;/code&gt; throws when &lt;code&gt;backupProgress.isComplete == true&lt;/code&gt;, the backup is unaffected and the error is silently ignored.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Passing non-default values of &lt;code&gt;pagesPerStep&lt;/code&gt; or &lt;code&gt;progress&lt;/code&gt; to the backup methods is an advanced API intended to provide additional capabilities to expert users. GRDB&#39;s backup API provides a faithful, low-level wrapper to the underlying SQLite online backup API. GRDB&#39;s documentation is not a comprehensive substitute for the official SQLite &lt;a href=&quot;https://www.sqlite.org/c3ref/backup_finish.html&quot;&gt;documentation of their backup API&lt;/a&gt;.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Interrupt a Database&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;interrupt()&lt;/code&gt; method&lt;/strong&gt; causes any pending database operation to abort and return at its earliest opportunity.&lt;/p&gt; 
&lt;p&gt;It can be called from any thread.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;dbQueue.interrupt()
dbPool.interrupt()
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;A call to &lt;code&gt;interrupt()&lt;/code&gt; that occurs when there are no running SQL statements is a no-op and has no effect on SQL statements that are started after &lt;code&gt;interrupt()&lt;/code&gt; returns.&lt;/p&gt; 
&lt;p&gt;A database operation that is interrupted will throw a DatabaseError with code &lt;code&gt;SQLITE_INTERRUPT&lt;/code&gt;. If the interrupted SQL operation is an INSERT, UPDATE, or DELETE that is inside an explicit transaction, then the entire transaction will be rolled back automatically. If the rolled back transaction was started by a transaction-wrapping method such as &lt;code&gt;DatabaseWriter.write&lt;/code&gt; or &lt;code&gt;Database.inTransaction&lt;/code&gt;, then all database accesses will throw a DatabaseError with code &lt;code&gt;SQLITE_ABORT&lt;/code&gt; until the wrapping method returns.&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.write { db in
    try Player(...).insert(db)     // throws SQLITE_INTERRUPT
    try Player(...).insert(db)     // not executed
}                                  // throws SQLITE_INTERRUPT

try dbQueue.write { db in
    do {
        try Player(...).insert(db) // throws SQLITE_INTERRUPT
    } catch { }
}                                  // throws SQLITE_ABORT

try dbQueue.write { db in
    do {
        try Player(...).insert(db) // throws SQLITE_INTERRUPT
    } catch { }
    try Player(...).insert(db)     // throws SQLITE_ABORT
}                                  // throws SQLITE_ABORT
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can catch both &lt;code&gt;SQLITE_INTERRUPT&lt;/code&gt; and &lt;code&gt;SQLITE_ABORT&lt;/code&gt; errors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try dbPool.write { db in ... }
} catch DatabaseError.SQLITE_INTERRUPT, DatabaseError.SQLITE_ABORT {
    // Oops, the database was interrupted.
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;For more information, see &lt;a href=&quot;https://www.sqlite.org/c3ref/interrupt.html&quot;&gt;Interrupt A Long-Running Query&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Avoiding SQL Injection&lt;/h2&gt; 
&lt;p&gt;SQL injection is a technique that lets an attacker nuke your database.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/exploits_of_a_mom.png&quot; alt=&quot;XKCD: Exploits of a Mom&quot; /&gt;&lt;/p&gt; 
 &lt;p&gt;&lt;a href=&quot;https://xkcd.com/327/&quot;&gt;https://xkcd.com/327/&lt;/a&gt;&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;Here is an example of code that is vulnerable to SQL injection:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// BAD BAD BAD
let id = 1
let name = textField.text
try dbQueue.write { db in
    try db.execute(sql: &quot;UPDATE students SET name = &#39;\(name)&#39; WHERE id = \(id)&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If the user enters a funny string like &lt;code&gt;Robert&#39;; DROP TABLE students; --&lt;/code&gt;, SQLite will see the following SQL, and drop your database table instead of updating a name as intended:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;UPDATE students SET name = &#39;Robert&#39;;
DROP TABLE students;
--&#39; WHERE id = 1
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;To avoid those problems, &lt;strong&gt;never embed raw values in your SQL queries&lt;/strong&gt;. The only correct technique is to provide &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#executing-updates&quot;&gt;arguments&lt;/a&gt; to your raw SQL queries:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name = textField.text
try dbQueue.write { db in
    // Good
    try db.execute(
        sql: &quot;UPDATE students SET name = ? WHERE id = ?&quot;,
        arguments: [name, id])
    
    // Just as good
    try db.execute(
        sql: &quot;UPDATE students SET name = :name WHERE id = :id&quot;,
        arguments: [&quot;name&quot;: name, &quot;id&quot;: id])
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When you use &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#records&quot;&gt;records&lt;/a&gt; and the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;, GRDB always prevents SQL injection for you:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let id = 1
let name = textField.text
try dbQueue.write { db in
    if var student = try Student.fetchOne(db, id: id) {
        student.name = name
        try student.update(db)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Error Handling&lt;/h2&gt; 
&lt;p&gt;GRDB can throw &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databaseerror&quot;&gt;DatabaseError&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#recorderror&quot;&gt;RecordError&lt;/a&gt;, &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#rowdecodingerror&quot;&gt;RowDecodingError&lt;/a&gt;, or crash your program with a &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fatal-errors&quot;&gt;fatal error&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Considering that a local database is not some JSON loaded from a remote server, GRDB focuses on &lt;strong&gt;trusted databases&lt;/strong&gt;. Dealing with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-to-deal-with-untrusted-inputs&quot;&gt;untrusted databases&lt;/a&gt; requires extra care.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databaseerror&quot;&gt;DatabaseError&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#recorderror&quot;&gt;RecordError&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#rowdecodingerror&quot;&gt;RowDecodingError&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fatal-errors&quot;&gt;Fatal Errors&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-to-deal-with-untrusted-inputs&quot;&gt;How to Deal with Untrusted Inputs&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#error-log&quot;&gt;Error Log&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;DatabaseError&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseerror&quot;&gt;&lt;code&gt;DatabaseError&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;DatabaseError&lt;/strong&gt; are thrown on SQLite errors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try Pet(masterId: 1, name: &quot;Bobby&quot;).insert(db)
} catch let error as DatabaseError {
    // The SQLite error code: 19 (SQLITE_CONSTRAINT)
    error.resultCode
    
    // The extended error code: 787 (SQLITE_CONSTRAINT_FOREIGNKEY)
    error.extendedResultCode
    
    // The eventual SQLite message: FOREIGN KEY constraint failed
    error.message
    
    // The eventual erroneous SQL query
    // &quot;INSERT INTO pet (masterId, name) VALUES (?, ?)&quot;
    error.sql
    
    // The eventual SQL arguments
    // [1, &quot;Bobby&quot;]
    error.arguments
    
    // Full error description
    // &amp;gt; SQLite error 19: FOREIGN KEY constraint failed -
    // &amp;gt; while executing `INSERT INTO pet (masterId, name) VALUES (?, ?)`
    error.description
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If you want to see statement arguments in the error description, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/configuration/publicstatementarguments&quot;&gt;make statement arguments public&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;SQLite uses &lt;a href=&quot;https://www.sqlite.org/rescode.html&quot;&gt;results codes&lt;/a&gt; to distinguish between various errors&lt;/strong&gt;.&lt;/p&gt; 
&lt;p&gt;You can catch a DatabaseError and match on result codes:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try ...
} catch let error as DatabaseError {
    switch error {
    case DatabaseError.SQLITE_CONSTRAINT_FOREIGNKEY:
        // foreign key constraint error
    case DatabaseError.SQLITE_CONSTRAINT:
        // any other constraint error
    default:
        // any other database error
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also directly match errors on result codes:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try ...
} catch DatabaseError.SQLITE_CONSTRAINT_FOREIGNKEY {
    // foreign key constraint error
} catch DatabaseError.SQLITE_CONSTRAINT {
    // any other constraint error
} catch {
    // any other database error
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Each DatabaseError has two codes: an &lt;code&gt;extendedResultCode&lt;/code&gt; (see &lt;a href=&quot;https://www.sqlite.org/rescode.html#extended_result_code_list&quot;&gt;extended result code&lt;/a&gt;), and a less precise &lt;code&gt;resultCode&lt;/code&gt; (see &lt;a href=&quot;https://www.sqlite.org/rescode.html#primary_result_code_list&quot;&gt;primary result code&lt;/a&gt;). Extended result codes are refinements of primary result codes, as &lt;code&gt;SQLITE_CONSTRAINT_FOREIGNKEY&lt;/code&gt; is to &lt;code&gt;SQLITE_CONSTRAINT&lt;/code&gt;, for example.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: SQLite has progressively introduced extended result codes across its versions. The &lt;a href=&quot;http://www.sqlite.org/changes.html&quot;&gt;SQLite release notes&lt;/a&gt; are unfortunately not quite clear about that: write your handling of extended result codes with care.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h3&gt;RecordError&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/recorderror&quot;&gt;&lt;code&gt;RecordError&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;RecordError&lt;/strong&gt; is thrown by the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; protocol when the &lt;code&gt;update&lt;/code&gt; method could not find any row to update:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try player.update(db)
} catch let RecordError.recordNotFound(databaseTableName: table, key: key) {
    print(&quot;Key \(key) was not found in table \(table).&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;RecordError&lt;/strong&gt; is also thrown by the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; protocol when the &lt;code&gt;find&lt;/code&gt; method does not find any record:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    let player = try Player.find(db, id: 42)
} catch let RecordError.recordNotFound(databaseTableName: table, key: key) {
    print(&quot;Key \(key) was not found in table \(table).&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;RowDecodingError&lt;/h3&gt; 
&lt;p&gt;📖 &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/rowdecodingerror&quot;&gt;&lt;code&gt;RowDecodingError&lt;/code&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;RowDecodingError&lt;/strong&gt; is thrown when the application can not decode a value from a database row. For example:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let row = try Row.fetchOne(db, sql: &quot;SELECT NULL AS name&quot;)!
// RowDecodingError: could not decode String from database value NULL.
let name = try row.decode(String.self, forColumn: &quot;name&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Fatal Errors&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Fatal errors notify that the program, or the database, has to be changed.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;They uncover programmer errors, false assumptions, and prevent misuses. Here are a few examples:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;The code asks for a non-optional value, when the database contains NULL:&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// fatal error: could not convert NULL to String.
let name: String = row[&quot;name&quot;]
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Solution: fix the contents of the database, use &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/columndefinition/notnull(onconflict:)&quot;&gt;NOT NULL constraints&lt;/a&gt;, or load an optional:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String? = row[&quot;name&quot;]
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Conversion from database value to Swift type fails:&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// fatal error: could not convert &quot;Mom’s birthday&quot; to Date.
let date: Date = row[&quot;date&quot;]

// fatal error: could not convert &quot;&quot; to URL.
let url: URL = row[&quot;url&quot;]
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Solution: fix the contents of the database, or use &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; to handle all possible cases:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let dbValue: DatabaseValue = row[&quot;date&quot;]
if dbValue.isNull {
    // Handle NULL
} else if let date = Date.fromDatabaseValue(dbValue) {
    // Handle valid date
} else {
    // Handle invalid date
}
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;The database can&#39;t guarantee that the code does what it says:&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// fatal error: table player has no unique index on column email
try Player.deleteOne(db, key: [&quot;email&quot;: &quot;arthur@example.com&quot;])
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Solution: add a unique index to the player.email column, or use the &lt;code&gt;deleteAll&lt;/code&gt; method to make it clear that you may delete more than one row:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try Player.filter { $0.email == &quot;arthur@example.com&quot; }.deleteAll(db)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Database connections are not reentrant:&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// fatal error: Database methods are not reentrant.
dbQueue.write { db in
    dbQueue.write { db in
        ...
    }
}
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Solution: avoid reentrancy, and instead pass a database connection along.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;How to Deal with Untrusted Inputs&lt;/h3&gt; 
&lt;p&gt;Let&#39;s consider the code below:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let sql = &quot;SELECT ...&quot;

// Some untrusted arguments for the query
let arguments: [String: Any] = ...
let rows = try Row.fetchCursor(db, sql: sql, arguments: StatementArguments(arguments))

while let row = try rows.next() {
    // Some untrusted database value:
    let date: Date? = row[0]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;It has two opportunities to throw fatal errors:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Untrusted arguments&lt;/strong&gt;: The dictionary may contain values that do not conform to the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#values&quot;&gt;DatabaseValueConvertible protocol&lt;/a&gt;, or may miss keys required by the statement.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Untrusted database content&lt;/strong&gt;: The row may contain a non-null value that can&#39;t be turned into a date.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;In such a situation, you can still avoid fatal errors by exposing and handling each failure point, one level down in the GRDB API:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Untrusted arguments
if let arguments = StatementArguments(arguments) {
    let statement = try db.makeStatement(sql: sql)
    try statement.setArguments(arguments)
    
    var cursor = try Row.fetchCursor(statement)
    while let row = try iterator.next() {
        // Untrusted database content
        let dbValue: DatabaseValue = row[0]
        if dbValue.isNull {
            // Handle NULL
        if let date = Date.fromDatabaseValue(dbValue) {
            // Handle valid date
        } else {
            // Handle invalid date
        }
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;&lt;code&gt;Statement&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databasevalue&quot;&gt;DatabaseValue&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;h3&gt;Error Log&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;SQLite can be configured to invoke a callback function containing an error code and a terse error message whenever anomalies occur.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;This global error callback must be configured early in the lifetime of your application:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Database.logError = { (resultCode, message) in
    NSLog(&quot;%@&quot;, &quot;SQLite error \(resultCode): \(message)&quot;)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Database.logError must be set before any database connection is opened. This includes the connections that your application opens with GRDB, but also connections opened by other tools, such as third-party libraries. Setting it after a connection has been opened is an SQLite misuse, and has no effect.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;See &lt;a href=&quot;https://sqlite.org/errlog.html&quot;&gt;The Error And Warning Log&lt;/a&gt; for more information.&lt;/p&gt; 
&lt;h2&gt;Unicode&lt;/h2&gt; 
&lt;p&gt;SQLite lets you store unicode strings in the database.&lt;/p&gt; 
&lt;p&gt;However, SQLite does not provide any unicode-aware string transformations or comparisons.&lt;/p&gt; 
&lt;h3&gt;Unicode functions&lt;/h3&gt; 
&lt;p&gt;The &lt;code&gt;UPPER&lt;/code&gt; and &lt;code&gt;LOWER&lt;/code&gt; built-in SQLite functions are not unicode-aware:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// &quot;JéRôME&quot;
try String.fetchOne(db, sql: &quot;SELECT UPPER(&#39;Jérôme&#39;)&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;GRDB extends SQLite with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#custom-sql-functions-and-aggregates&quot;&gt;SQL functions&lt;/a&gt; that call the Swift built-in string functions &lt;code&gt;capitalized&lt;/code&gt;, &lt;code&gt;lowercased&lt;/code&gt;, &lt;code&gt;uppercased&lt;/code&gt;, &lt;code&gt;localizedCapitalized&lt;/code&gt;, &lt;code&gt;localizedLowercased&lt;/code&gt; and &lt;code&gt;localizedUppercased&lt;/code&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// &quot;JÉRÔME&quot;
let uppercased = DatabaseFunction.uppercase
try String.fetchOne(db, sql: &quot;SELECT \(uppercased.name)(&#39;Jérôme&#39;)&quot;)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Those unicode-aware string functions are also readily available in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sql-functions&quot;&gt;query interface&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Player.select { $0.name.uppercased }
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;String Comparison&lt;/h3&gt; 
&lt;p&gt;SQLite compares strings in many occasions: when you sort rows according to a string column, or when you use a comparison operator such as &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;&amp;lt;=&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;The comparison result comes from a &lt;em&gt;collating function&lt;/em&gt;, or &lt;em&gt;collation&lt;/em&gt;. SQLite comes with three built-in collations that do not support Unicode: &lt;a href=&quot;https://www.sqlite.org/datatype3.html#collation&quot;&gt;binary, nocase, and rtrim&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;GRDB comes with five extra collations that leverage unicode-aware comparisons based on the standard Swift String comparison functions and operators:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;unicodeCompare&lt;/code&gt; (uses the built-in &lt;code&gt;&amp;lt;=&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt; Swift operators)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;caseInsensitiveCompare&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;localizedCaseInsensitiveCompare&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;localizedCompare&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;localizedStandardCompare&lt;/code&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;A collation can be applied to a table column. All comparisons involving this column will then automatically trigger the comparison function:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try db.create(table: &quot;player&quot;) { t in
    // Guarantees case-insensitive email unicity
    t.column(&quot;email&quot;, .text).unique().collate(.nocase)
    
    // Sort names in a localized case insensitive way
    t.column(&quot;name&quot;, .text).collate(.localizedCaseInsensitiveCompare)
}

// Players are sorted in a localized case insensitive way:
let players = try Player.order(\.name).fetchAll(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: SQLite &lt;em&gt;requires&lt;/em&gt; host applications to provide the definition of any collation other than binary, nocase and rtrim. When a database file has to be shared or migrated to another SQLite library of platform (such as the Android version of your application), make sure you provide a compatible collation.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;If you can&#39;t or don&#39;t want to define the comparison behavior of a column (see warning above), you can still use an explicit collation in SQL requests and in the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#the-query-interface&quot;&gt;query interface&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let collation = DatabaseCollation.localizedCaseInsensitiveCompare
let players = try Player.fetchAll(db,
    sql: &quot;SELECT * FROM player ORDER BY name COLLATE \(collation.name))&quot;)
let players = try Player.order { $0.name.collating(collation) }.fetchAll(db)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;strong&gt;You can also define your own collations&lt;/strong&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let collation = DatabaseCollation(&quot;customCollation&quot;) { (lhs, rhs) -&amp;gt; NSComparisonResult in
    // return the comparison of lhs and rhs strings.
}

// Make the collation available to a database connection
var config = Configuration()
config.prepareDatabase { db in
    db.add(collation: collation)
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Memory Management&lt;/h2&gt; 
&lt;p&gt;Both SQLite and GRDB use non-essential memory that help them perform better.&lt;/p&gt; 
&lt;p&gt;You can reclaim this memory with the &lt;code&gt;releaseMemory&lt;/code&gt; method:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Release as much memory as possible.
dbQueue.releaseMemory()
dbPool.releaseMemory()
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This method blocks the current thread until all current database accesses are completed, and the memory collected.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: If &lt;code&gt;DatabasePool.releaseMemory()&lt;/code&gt; is called while a long read is performed concurrently, then no other read access will be possible until this long read has completed, and the memory has been released. If this does not suit your application needs, look for the asynchronous options below:&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;p&gt;You can release memory in an asynchronous way as well:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// On a DatabaseQueue
dbQueue.asyncWriteWithoutTransaction { db in
    db.releaseMemory()
}

// On a DatabasePool
dbPool.releaseMemoryEventually()
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;&lt;code&gt;DatabasePool.releaseMemoryEventually()&lt;/code&gt; does not block the current thread, and does not prevent concurrent database accesses. In exchange for this convenience, you don&#39;t know when memory has been freed.&lt;/p&gt; 
&lt;h3&gt;Memory Management on iOS&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;The iOS operating system likes applications that do not consume much memory.&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasequeue&quot;&gt;Database queues&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;pools&lt;/a&gt; automatically free non-essential memory when the application receives a memory warning, and when the application enters background.&lt;/p&gt; 
&lt;p&gt;You can opt out of this automatic memory management:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.automaticMemoryManagement = false
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config) // or DatabasePool
&lt;/code&gt;&lt;/pre&gt; 
&lt;h1&gt;FAQ&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-opening-connections&quot;&gt;FAQ: Opening Connections&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-create-a-database-in-my-application&quot;&gt;How do I create a database in my application?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-open-a-database-stored-as-a-resource-of-my-application&quot;&gt;How do I open a database stored as a resource of my application?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-close-a-database-connection&quot;&gt;How do I close a database connection?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-sql&quot;&gt;FAQ: SQL&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-print-a-request-as-sql&quot;&gt;How do I print a request as SQL?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-general&quot;&gt;FAQ: General&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-monitor-the-duration-of-database-statements-execution&quot;&gt;How do I monitor the duration of database statements execution?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#what-are-experimental-features&quot;&gt;What Are Experimental Features?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#does-grdb-support-library-evolution-and-abi-stability&quot;&gt;Does GRDB support library evolution and ABI stability?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-associations&quot;&gt;FAQ: Associations&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are associated to another record?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-not-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are NOT associated to another record?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-select-only-one-column-of-an-associated-record&quot;&gt;How do I select only one column of an associated record?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-valueobservation&quot;&gt;FAQ: ValueObservation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#why-is-valueobservation-not-publishing-value-changes&quot;&gt;Why is ValueObservation not publishing value changes?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq-errors&quot;&gt;FAQ: Errors&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#generic-parameter-t-could-not-be-inferred&quot;&gt;Generic parameter &#39;T&#39; could not be inferred&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#mutation-of-captured-var-in-concurrently-executing-code&quot;&gt;Mutation of captured var in concurrently-executing code&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-1-no-such-column&quot;&gt;SQLite error 1 &quot;no such column&quot;&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-10-disk-io-error-sqlite-error-23-not-authorized&quot;&gt;SQLite error 10 &quot;disk I/O error&quot;, SQLite error 23 &quot;not authorized&quot;&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-21-wrong-number-of-statement-arguments-with-like-queries&quot;&gt;SQLite error 21 &quot;wrong number of statement arguments&quot; with LIKE queries&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;FAQ: Opening Connections&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-create-a-database-in-my-application&quot;&gt;How do I create a database in my application?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-open-a-database-stored-as-a-resource-of-my-application&quot;&gt;How do I open a database stored as a resource of my application?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-close-a-database-connection&quot;&gt;How do I close a database connection?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;How do I create a database in my application?&lt;/h3&gt; 
&lt;p&gt;First choose a proper location for the database file. Document-based applications will let the user pick a location. Apps that use the database as a global storage will prefer the Application Support directory.&lt;/p&gt; 
&lt;p&gt;The sample code below creates or opens a database file inside its dedicated directory (a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseconnections&quot;&gt;recommended practice&lt;/a&gt;). On the first run, a new empty database file is created. On subsequent runs, the database file already exists, so it just opens a connection:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// HOW TO create an empty database, or open an existing database file

// Create the &quot;Application Support/MyDatabase&quot; directory
let fileManager = FileManager.default
let appSupportURL = try fileManager.url(
    for: .applicationSupportDirectory, in: .userDomainMask,
    appropriateFor: nil, create: true) 
let directoryURL = appSupportURL.appendingPathComponent(&quot;MyDatabase&quot;, isDirectory: true)
try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true)

// Open or create the database
let databaseURL = directoryURL.appendingPathComponent(&quot;db.sqlite&quot;)
let dbQueue = try DatabaseQueue(path: databaseURL.path)
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;How do I open a database stored as a resource of my application?&lt;/h3&gt; 
&lt;p&gt;Open a read-only connection to your resource:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// HOW TO open a read-only connection to a database resource

// Get the path to the database resource.
if let dbPath = Bundle.main.path(forResource: &quot;db&quot;, ofType: &quot;sqlite&quot;) {
    // If the resource exists, open a read-only connection.
    // Writes are disallowed because resources can not be modified. 
    var config = Configuration()
    config.readonly = true
    let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
} else {
    // The database resource can not be found.
    // Fix your setup, or report the problem to the user. 
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;How do I close a database connection?&lt;/h3&gt; 
&lt;p&gt;Database connections are automatically closed when &lt;code&gt;DatabaseQueue&lt;/code&gt; or &lt;code&gt;DatabasePool&lt;/code&gt; instances are deinitialized.&lt;/p&gt; 
&lt;p&gt;If the correct execution of your program depends on precise database closing, perform an explicit call to &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasereader/close()&quot;&gt;&lt;code&gt;close()&lt;/code&gt;&lt;/a&gt;. This method may fail and create zombie connections, so please check its detailed documentation.&lt;/p&gt; 
&lt;h2&gt;FAQ: SQL&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-print-a-request-as-sql&quot;&gt;How do I print a request as SQL?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;How do I print a request as SQL?&lt;/h3&gt; 
&lt;p&gt;When you want to debug a request that does not deliver the expected results, you may want to print the SQL that is actually executed.&lt;/p&gt; 
&lt;p&gt;You can compile the request into a prepared &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;&lt;code&gt;Statement&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try dbQueue.read { db in
    let request = Player.filter { $0.email == &quot;arthur@example.com&quot; }
    let statement = try request.makePreparedRequest(db).statement
    print(statement) // SELECT * FROM player WHERE email = ?
    print(statement.arguments) // [&quot;arthur@example.com&quot;]
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Another option is to setup a tracing function that prints out the executed SQL requests. For example, provide a tracing function when you connect to the database:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Prints all SQL statements
var config = Configuration()
config.prepareDatabase { db in
    db.trace { print($0) }
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)

try dbQueue.read { db in
    // Prints &quot;SELECT * FROM player WHERE email = ?&quot;
    let players = try Player.filter { $0.email == &quot;arthur@example.com&quot; }.fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If you want to see statement arguments such as &lt;code&gt;&#39;arthur@example.com&#39;&lt;/code&gt; in the logged statements, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/configuration/publicstatementarguments&quot;&gt;make statement arguments public&lt;/a&gt;.&lt;/p&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: the generated SQL may change between GRDB releases, without notice: don&#39;t have your application rely on any specific SQL output.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;FAQ: General&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-monitor-the-duration-of-database-statements-execution&quot;&gt;How do I monitor the duration of database statements execution?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#what-are-experimental-features&quot;&gt;What Are Experimental Features?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#does-grdb-support-library-evolution-and-abi-stability&quot;&gt;Does GRDB support library evolution and ABI stability?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;How do I monitor the duration of database statements execution?&lt;/h3&gt; 
&lt;p&gt;Use the &lt;code&gt;trace(options:_:)&lt;/code&gt; method, with the &lt;code&gt;.profile&lt;/code&gt; option:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var config = Configuration()
config.prepareDatabase { db in
    db.trace(options: .profile) { event in
        // Prints all SQL statements with their duration
        print(event)
        
        // Access to detailed profiling information
        if case let .profile(statement, duration) = event, duration &amp;gt; 0.5 {
            print(&quot;Slow query: \(statement.sql)&quot;)
        }
    }
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)

try dbQueue.read { db in
    let players = try Player.filter { $0.email == &quot;arthur@example.com&quot; }.fetchAll(db)
    // Prints &quot;0.003s SELECT * FROM player WHERE email = ?&quot;
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If you want to see statement arguments such as &lt;code&gt;&#39;arthur@example.com&#39;&lt;/code&gt; in the logged statements, &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/configuration/publicstatementarguments&quot;&gt;make statement arguments public&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;What Are Experimental Features?&lt;/h3&gt; 
&lt;p&gt;Since GRDB 1.0, all backwards compatibility guarantees of &lt;a href=&quot;http://semver.org&quot;&gt;semantic versioning&lt;/a&gt; apply: no breaking change will happen until the next major version of the library.&lt;/p&gt; 
&lt;p&gt;There is an exception, though: &lt;em&gt;experimental features&lt;/em&gt;, marked with the &quot;&lt;strong&gt;🔥 EXPERIMENTAL&lt;/strong&gt;&quot; badge. Those are advanced features that are too young, or lack user feedback. They are not stabilized yet.&lt;/p&gt; 
&lt;p&gt;Those experimental features are not protected by semantic versioning, and may break between two minor releases of the library. To help them becoming stable, &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues&quot;&gt;your feedback&lt;/a&gt; is greatly appreciated.&lt;/p&gt; 
&lt;h3&gt;Does GRDB support library evolution and ABI stability?&lt;/h3&gt; 
&lt;p&gt;No, GRDB does not support library evolution and ABI stability. The only promise is API stability according to &lt;a href=&quot;http://semver.org&quot;&gt;semantic versioning&lt;/a&gt;, with an exception for &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#what-are-experimental-features&quot;&gt;experimental features&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Yet, GRDB can be built with the &quot;Build Libraries for Distribution&quot; Xcode option (&lt;code&gt;BUILD_LIBRARY_FOR_DISTRIBUTION&lt;/code&gt;), so that you can build binary frameworks at your convenience.&lt;/p&gt; 
&lt;h2&gt;FAQ: Associations&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are associated to another record?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-not-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are NOT associated to another record?&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-select-only-one-column-of-an-associated-record&quot;&gt;How do I select only one column of an associated record?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;How do I filter records and only keep those that are associated to another record?&lt;/h3&gt; 
&lt;p&gt;Let&#39;s say you have two record types, &lt;code&gt;Book&lt;/code&gt; and &lt;code&gt;Author&lt;/code&gt;, and you want to only fetch books that have an author, and discard anonymous books.&lt;/p&gt; 
&lt;p&gt;We start by defining the association between books and authors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Book: TableRecord {
    ...
    static let author = belongsTo(Author.self)
}

struct Author: TableRecord {
    ...
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;And then we can write our request and only fetch books that have an author, discarding anonymous ones:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let books: [Book] = try dbQueue.read { db in
    // SELECT book.* FROM book 
    // JOIN author ON author.id = book.authorID
    let request = Book.joining(required: Book.author)
    return try request.fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Note how this request does not use the &lt;code&gt;filter&lt;/code&gt; method. Indeed, we don&#39;t have any condition to express on any column. Instead, we just need to &quot;require that a book can be joined to its author&quot;.&lt;/p&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-not-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are NOT associated to another record?&lt;/a&gt; below for the opposite question.&lt;/p&gt; 
&lt;h3&gt;How do I filter records and only keep those that are NOT associated to another record?&lt;/h3&gt; 
&lt;p&gt;Let&#39;s say you have two record types, &lt;code&gt;Book&lt;/code&gt; and &lt;code&gt;Author&lt;/code&gt;, and you want to only fetch anonymous books that do not have any author.&lt;/p&gt; 
&lt;p&gt;We start by defining the association between books and authors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Book: TableRecord {
    ...
    static let author = belongsTo(Author.self)
}

struct Author: TableRecord {
    ...
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;And then we can write our request and only fetch anonymous books that don&#39;t have any author:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let books: [Book] = try dbQueue.read { db in
    // SELECT book.* FROM book
    // LEFT JOIN author ON author.id = book.authorID
    // WHERE author.id IS NULL
    let authorAlias = TableAlias&amp;lt;Author&amp;gt;()
    let request = Book
        .joining(optional: Book.author.aliased(authorAlias))
        .filter(!authorAlias.exists)
    return try request.fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This request uses a TableAlias in order to be able to filter on the eventual associated author. We make sure that the &lt;code&gt;Author.primaryKey&lt;/code&gt; is nil, which is another way to say it does not exist: the book has no author.&lt;/p&gt; 
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#how-do-i-filter-records-and-only-keep-those-that-are-associated-to-another-record&quot;&gt;How do I filter records and only keep those that are associated to another record?&lt;/a&gt; above for the opposite question.&lt;/p&gt; 
&lt;h3&gt;How do I select only one column of an associated record?&lt;/h3&gt; 
&lt;p&gt;Let&#39;s say you have two record types, &lt;code&gt;Book&lt;/code&gt; and &lt;code&gt;Author&lt;/code&gt;, and you want to fetch all books with their author name, but not the full associated author records.&lt;/p&gt; 
&lt;p&gt;We start by defining the association between books and authors:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Book: Decodable, TableRecord {
    ...
    static let author = belongsTo(Author.self)
}

struct Author: Decodable, TableRecord {
    ...
    enum Columns {
        static let name = Column(CodingKeys.name)
    }
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;And then we can write our request and the ad-hoc record that decodes it:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct BookInfo: Decodable, FetchableRecord {
    var book: Book
    var authorName: String? // nil when the book is anonymous
    
    static func all() -&amp;gt; QueryInterfaceRequest&amp;lt;BookInfo&amp;gt; {
        // SELECT book.*, author.name AS authorName
        // FROM book
        // LEFT JOIN author ON author.id = book.authorID
        return Book
            .annotated(withOptional: Book.author.select { 
                $0.name.forKey(CodingKeys.authorName)
            })
            .asRequest(of: BookInfo.self)
    }
}

let bookInfos: [BookInfo] = try dbQueue.read { db in
    BookInfo.all().fetchAll(db)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;By defining the request as a static method of BookInfo, you have access to the private &lt;code&gt;CodingKeys.authorName&lt;/code&gt;, and a compiler-checked SQL column name.&lt;/p&gt; 
&lt;p&gt;By using the &lt;code&gt;annotated(withOptional:)&lt;/code&gt; method, you append the author name to the top-level selection that can be decoded by the ad-hoc record.&lt;/p&gt; 
&lt;p&gt;By using &lt;code&gt;asRequest(of:)&lt;/code&gt;, you enhance the type-safety of your request.&lt;/p&gt; 
&lt;h2&gt;FAQ: ValueObservation&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#why-is-valueobservation-not-publishing-value-changes&quot;&gt;Why is ValueObservation not publishing value changes?&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Why is ValueObservation not publishing value changes?&lt;/h3&gt; 
&lt;p&gt;Sometimes it looks that a &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/valueobservation&quot;&gt;ValueObservation&lt;/a&gt; does not notify the changes you expect.&lt;/p&gt; 
&lt;p&gt;There may be four possible reasons for this:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;The expected changes were not committed into the database.&lt;/li&gt; 
 &lt;li&gt;The expected changes were committed into the database, but were quickly overwritten.&lt;/li&gt; 
 &lt;li&gt;The observation was stopped.&lt;/li&gt; 
 &lt;li&gt;The observation does not track the expected database region.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;To answer the first two questions, look at SQL statements executed by the database. This is done when you open the database connection:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Prints all SQL statements
var config = Configuration()
config.prepareDatabase { db in
    db.trace { print(&quot;SQL: \($0)&quot;) }
}
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;If, after that, you are convinced that the expected changes were committed into the database, and not overwritten soon after, trace observation events:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let observation = ValueObservation
    .tracking { db in ... }
    .print() // &amp;lt;- trace observation events
let cancellable = observation.start(...)
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Look at the observation logs which start with &lt;code&gt;cancel&lt;/code&gt; or &lt;code&gt;failure&lt;/code&gt;: maybe the observation was cancelled by your app, or did fail with an error.&lt;/p&gt; 
&lt;p&gt;Look at the observation logs which start with &lt;code&gt;value&lt;/code&gt;: make sure, again, that the expected value was not actually notified, then overwritten.&lt;/p&gt; 
&lt;p&gt;Finally, look at the observation logs which start with &lt;code&gt;tracked region&lt;/code&gt;. Does the printed database region cover the expected changes?&lt;/p&gt; 
&lt;p&gt;For example:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;empty&lt;/code&gt;: The empty region, which tracks nothing and never triggers the observation.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;player(*)&lt;/code&gt;: The full &lt;code&gt;player&lt;/code&gt; table&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;player(id,name)&lt;/code&gt;: The &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; columns of the &lt;code&gt;player&lt;/code&gt; table&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;player(id,name)[1]&lt;/code&gt;: The &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; columns of the row with id 1 in the &lt;code&gt;player&lt;/code&gt; table&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;player(*),team(*)&lt;/code&gt;: Both the full &lt;code&gt;player&lt;/code&gt; and &lt;code&gt;team&lt;/code&gt; tables&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;If you happen to use the &lt;code&gt;ValueObservation.trackingConstantRegion(_:)&lt;/code&gt; method and see a mismatch between the tracked region and your expectation, then change the definition of your observation by using &lt;code&gt;tracking(_:)&lt;/code&gt;. You should witness that the logs which start with &lt;code&gt;tracked region&lt;/code&gt; now evolve in order to include the expected changes, and that you get the expected notifications.&lt;/p&gt; 
&lt;p&gt;If after all those steps (thanks you!), your observation is still failing you, please &lt;a href=&quot;https://github.com/groue/GRDB.swift/issues/new&quot;&gt;open an issue&lt;/a&gt; and provide a &lt;a href=&quot;https://stackoverflow.com/help/minimal-reproducible-example&quot;&gt;minimal reproducible example&lt;/a&gt;!&lt;/p&gt; 
&lt;h2&gt;FAQ: Errors&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;⬆️ &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#generic-parameter-t-could-not-be-inferred&quot;&gt;Generic parameter &#39;T&#39; could not be inferred&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#mutation-of-captured-var-in-concurrently-executing-code&quot;&gt;Mutation of captured var in concurrently-executing code&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-1-no-such-column&quot;&gt;SQLite error 1 &quot;no such column&quot;&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-10-disk-io-error-sqlite-error-23-not-authorized&quot;&gt;SQLite error 10 &quot;disk I/O error&quot;, SQLite error 23 &quot;not authorized&quot;&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#sqlite-error-21-wrong-number-of-statement-arguments-with-like-queries&quot;&gt;SQLite error 21 &quot;wrong number of statement arguments&quot; with LIKE queries&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Generic parameter &#39;T&#39; could not be inferred&lt;/h3&gt; 
&lt;p&gt;You may get this error when using the &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt; methods of database queues and pools:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Generic parameter &#39;T&#39; could not be inferred
let string = try dbQueue.read { db in
    let result = try String.fetchOne(db, ...)
    return result
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This is a limitation of the Swift compiler.&lt;/p&gt; 
&lt;p&gt;The general workaround is to explicitly declare the type of the closure result:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// General Workaround
let string = try dbQueue.read { db -&amp;gt; String? in
    let result = try String.fetchOne(db, ...)
    return result
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;You can also, when possible, write a single-line closure:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Single-line closure workaround:
let string = try dbQueue.read { db in
    try String.fetchOne(db, ...)
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;Mutation of captured var in concurrently-executing code&lt;/h3&gt; 
&lt;p&gt;The &lt;code&gt;insert&lt;/code&gt; and &lt;code&gt;save&lt;/code&gt; &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;persistence methods&lt;/a&gt; can trigger a compiler error in async contexts:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var player = Player(id: nil, name: &quot;Arthur&quot;)
try await dbWriter.write { db in
    // Error: Mutation of captured var &#39;player&#39; in concurrently-executing code
    try player.insert(db)
}
print(player.id) // A non-nil id
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;When this happens, prefer the &lt;code&gt;inserted&lt;/code&gt; and &lt;code&gt;saved&lt;/code&gt; methods instead:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// OK
var player = Player(id: nil, name: &quot;Arthur&quot;)
player = try await dbWriter.write { [player] db in
    return try player.inserted(db)
}
print(player.id) // A non-nil id
&lt;/code&gt;&lt;/pre&gt; 
&lt;h3&gt;SQLite error 1 &quot;no such column&quot;&lt;/h3&gt; 
&lt;p&gt;This error message is self-explanatory: do check for misspelled or non-existing column names.&lt;/p&gt; 
&lt;p&gt;However, sometimes this error only happens when an app runs on a recent operating system (iOS 14+, Big Sur+, etc.) The error does not happen with previous ones.&lt;/p&gt; 
&lt;p&gt;When this is the case, there are two possible explanations:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt; &lt;p&gt;Maybe a column name is &lt;em&gt;really&lt;/em&gt; misspelled or missing from the database schema.&lt;/p&gt; &lt;p&gt;To find it, check the SQL statement that comes with the &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#databaseerror&quot;&gt;DatabaseError&lt;/a&gt;.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;Maybe the application is using the character &lt;code&gt;&quot;&lt;/code&gt; instead of the single quote &lt;code&gt;&#39;&lt;/code&gt; as the delimiter for string literals in raw SQL queries. Recent versions of SQLite have learned to tell about this deviation from the SQL standard, and this is why you are seeing this error.&lt;/p&gt; &lt;p&gt;For example: this is not standard SQL: &lt;code&gt;UPDATE player SET name = &quot;Arthur&quot;&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;The standard version is: &lt;code&gt;UPDATE player SET name = &#39;Arthur&#39;&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;It just happens that old versions of SQLite used to accept the former, non-standard version. Newer versions are able to reject it with an error.&lt;/p&gt; &lt;p&gt;The fix is to change the SQL statements run by the application: replace &lt;code&gt;&quot;&lt;/code&gt; with &lt;code&gt;&#39;&lt;/code&gt; in your string literals.&lt;/p&gt; &lt;p&gt;It may also be time to learn about statement arguments and &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#avoiding-sql-injection&quot;&gt;SQL injection&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name: String = ...

// NOT STANDARD (double quote)
try db.execute(sql: &quot;&quot;&quot;
    UPDATE player SET name = &quot;\(name)&quot;
    &quot;&quot;&quot;)

// STANDARD, BUT STILL NOT RECOMMENDED (single quote)
try db.execute(sql: &quot;UPDATE player SET name = &#39;\(name)&#39;&quot;)

// STANDARD, AND RECOMMENDED (statement arguments)
try db.execute(sql: &quot;UPDATE player SET name = ?&quot;, arguments: [name])

// STANDARD, AND RECOMMENDED (SQL interpolation)
try db.execute(literal: &quot;UPDATE player SET name = \(name)&quot;)
&lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;For more information, see &lt;a href=&quot;https://sqlite.org/quirks.html#double_quoted_string_literals_are_accepted&quot;&gt;Double-quoted String Literals Are Accepted&lt;/a&gt;, and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/configuration/acceptsdoublequotedstringliterals&quot;&gt;Configuration.acceptsDoubleQuotedStringLiterals&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;SQLite error 10 &quot;disk I/O error&quot;, SQLite error 23 &quot;not authorized&quot;&lt;/h3&gt; 
&lt;p&gt;Those errors may be the sign that SQLite can&#39;t access the database due to &lt;a href=&quot;https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files&quot;&gt;data protection&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;When your application should be able to run in the background on a locked device, it has to catch this error, and, for example, wait for &lt;a href=&quot;https://developer.apple.com/reference/uikit/uiapplicationdelegate/1623044-applicationprotecteddatadidbecom&quot;&gt;UIApplicationDelegate.applicationProtectedDataDidBecomeAvailable(_😃&lt;/a&gt; or &lt;a href=&quot;https://developer.apple.com/reference/uikit/uiapplicationprotecteddatadidbecomeavailable&quot;&gt;UIApplicationProtectedDataDidBecomeAvailable&lt;/a&gt; notification and retry the failed database operation.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do {
    try ...
} catch DatabaseError.SQLITE_IOERR, DatabaseError.SQLITE_AUTH {
    // Handle possible data protection error
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;This error can also be prevented altogether by using a more relaxed &lt;a href=&quot;https://developer.apple.com/reference/foundation/filemanager/1653059-file_protection_values&quot;&gt;file protection&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;SQLite error 21 &quot;wrong number of statement arguments&quot; with LIKE queries&lt;/h3&gt; 
&lt;p&gt;You may get the error &quot;wrong number of statement arguments&quot; when executing a LIKE query similar to:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name = textField.text
let players = try dbQueue.read { db in
    try Player.fetchAll(db, sql: &quot;SELECT * FROM player WHERE name LIKE &#39;%?%&#39;&quot;, arguments: [name])
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;The problem lies in the &lt;code&gt;&#39;%?%&#39;&lt;/code&gt; pattern.&lt;/p&gt; 
&lt;p&gt;SQLite only interprets &lt;code&gt;?&lt;/code&gt; as a parameter when it is a placeholder for a whole value (int, double, string, blob, null). In this incorrect query, &lt;code&gt;?&lt;/code&gt; is just a character in the &lt;code&gt;&#39;%?%&#39;&lt;/code&gt; string: it is not a query parameter, and is not processed in any way. See &lt;a href=&quot;https://www.sqlite.org/lang_expr.html#varparam&quot;&gt;https://www.sqlite.org/lang_expr.html#varparam&lt;/a&gt; for more information about SQLite parameters.&lt;/p&gt; 
&lt;p&gt;To fix the error, you can feed the request with the pattern itself, instead of the name:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let name = textField.text
let players: [Player] = try dbQueue.read { db in
    let pattern = &quot;%\(name)%&quot;
    return try Player.fetchAll(db, sql: &quot;SELECT * FROM player WHERE name LIKE ?&quot;, arguments: [pattern])
}
&lt;/code&gt;&lt;/pre&gt; 
&lt;h1&gt;Sample Code&lt;/h1&gt; 
&lt;ul&gt; 
 &lt;li&gt;The &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#documentation&quot;&gt;Documentation&lt;/a&gt; is full of GRDB snippets.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/DemoApps&quot;&gt;Demo Applications&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Open &lt;code&gt;GRDB.xcworkspace&lt;/code&gt;: it contains GRDB-enabled playgrounds to play with.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/groue/SortedDifference&quot;&gt;groue/SortedDifference&lt;/a&gt;: How to synchronize a database table with a JSON payload&lt;/li&gt; 
&lt;/ul&gt; 
&lt;hr /&gt; 
&lt;p&gt;&lt;strong&gt;Thanks&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;http://pierlis.com&quot;&gt;Pierlis&lt;/a&gt;, where we write great software.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/alextrob&quot;&gt;@alextrob&lt;/a&gt;, &lt;a href=&quot;https://github.com/alexwlchan&quot;&gt;@alexwlchan&lt;/a&gt;, &lt;a href=&quot;https://github.com/bellebethcooper&quot;&gt;@bellebethcooper&lt;/a&gt;, &lt;a href=&quot;https://github.com/bfad&quot;&gt;@bfad&lt;/a&gt;, &lt;a href=&quot;https://github.com/cfilipov&quot;&gt;@cfilipov&lt;/a&gt;, &lt;a href=&quot;https://github.com/charlesmchen-signal&quot;&gt;@charlesmchen-signal&lt;/a&gt;, &lt;a href=&quot;https://github.com/Chiliec&quot;&gt;@Chiliec&lt;/a&gt;, &lt;a href=&quot;https://github.com/chrisballinger&quot;&gt;@chrisballinger&lt;/a&gt;, &lt;a href=&quot;https://github.com/darrenclark&quot;&gt;@darrenclark&lt;/a&gt;, &lt;a href=&quot;https://github.com/davidkraus&quot;&gt;@davidkraus&lt;/a&gt;, &lt;a href=&quot;https://github.com/eburns-vmware&quot;&gt;@eburns-vmware&lt;/a&gt;, &lt;a href=&quot;https://github.com/felixscheinost&quot;&gt;@felixscheinost&lt;/a&gt;, &lt;a href=&quot;https://github.com/fpillet&quot;&gt;@fpillet&lt;/a&gt;, &lt;a href=&quot;https://github.com/gcox&quot;&gt;@gcox&lt;/a&gt;, &lt;a href=&quot;https://github.com/GetToSet&quot;&gt;@GetToSet&lt;/a&gt;, &lt;a href=&quot;https://github.com/gjeck&quot;&gt;@gjeck&lt;/a&gt;, &lt;a href=&quot;https://github.com/guidedways&quot;&gt;@guidedways&lt;/a&gt;, &lt;a href=&quot;https://github.com/gusrota&quot;&gt;@gusrota&lt;/a&gt;, &lt;a href=&quot;https://github.com/haikusw&quot;&gt;@haikusw&lt;/a&gt;, &lt;a href=&quot;https://github.com/hartbit&quot;&gt;@hartbit&lt;/a&gt;, &lt;a href=&quot;https://github.com/holsety&quot;&gt;@holsety&lt;/a&gt;, &lt;a href=&quot;https://github.com/jroselightricks&quot;&gt;@jroselightricks&lt;/a&gt;, &lt;a href=&quot;https://github.com/kdubb&quot;&gt;@kdubb&lt;/a&gt;, &lt;a href=&quot;https://github.com/kluufger&quot;&gt;@kluufger&lt;/a&gt;, &lt;a href=&quot;https://github.com/KyleLeneau&quot;&gt;@KyleLeneau&lt;/a&gt;, &lt;a href=&quot;https://github.com/layoutSubviews&quot;&gt;@layoutSubviews&lt;/a&gt;, &lt;a href=&quot;https://github.com/mallman&quot;&gt;@mallman&lt;/a&gt;, &lt;a href=&quot;https://github.com/MartinP7r&quot;&gt;@MartinP7r&lt;/a&gt;, &lt;a href=&quot;https://github.com/Marus&quot;&gt;@Marus&lt;/a&gt;, &lt;a href=&quot;https://github.com/mattgallagher&quot;&gt;@mattgallagher&lt;/a&gt;, &lt;a href=&quot;https://github.com/MaxDesiatov&quot;&gt;@MaxDesiatov&lt;/a&gt;, &lt;a href=&quot;https://github.com/michaelkirk-signal&quot;&gt;@michaelkirk-signal&lt;/a&gt;, &lt;a href=&quot;https://github.com/mtancock&quot;&gt;@mtancock&lt;/a&gt;, &lt;a href=&quot;https://github.com/pakko972&quot;&gt;@pakko972&lt;/a&gt;, &lt;a href=&quot;https://github.com/peter-ss&quot;&gt;@peter-ss&lt;/a&gt;, &lt;a href=&quot;https://github.com/pierlo&quot;&gt;@pierlo&lt;/a&gt;, &lt;a href=&quot;https://github.com/pocketpixels&quot;&gt;@pocketpixels&lt;/a&gt;, &lt;a href=&quot;https://github.com/pp5x&quot;&gt;@pp5x&lt;/a&gt;, &lt;a href=&quot;https://github.com/professordeng&quot;&gt;@professordeng&lt;/a&gt;, &lt;a href=&quot;https://github.com/robcas3&quot;&gt;@robcas3&lt;/a&gt;, &lt;a href=&quot;https://github.com/runhum&quot;&gt;@runhum&lt;/a&gt;, &lt;a href=&quot;https://github.com/sberrevoets&quot;&gt;@sberrevoets&lt;/a&gt;, &lt;a href=&quot;https://github.com/schveiguy&quot;&gt;@schveiguy&lt;/a&gt;, &lt;a href=&quot;https://github.com/SD10&quot;&gt;@SD10&lt;/a&gt;, &lt;a href=&quot;https://github.com/sobri909&quot;&gt;@sobri909&lt;/a&gt;, &lt;a href=&quot;https://github.com/sroddy&quot;&gt;@sroddy&lt;/a&gt;, &lt;a href=&quot;https://github.com/steipete&quot;&gt;@steipete&lt;/a&gt;, &lt;a href=&quot;https://github.com/swiftlyfalling&quot;&gt;@swiftlyfalling&lt;/a&gt;, &lt;a href=&quot;https://github.com/Timac&quot;&gt;@Timac&lt;/a&gt;, &lt;a href=&quot;https://github.com/tternes&quot;&gt;@tternes&lt;/a&gt;, &lt;a href=&quot;https://github.com/valexa&quot;&gt;@valexa&lt;/a&gt;, &lt;a href=&quot;https://github.com/wuyuehyang&quot;&gt;@wuyuehyang&lt;/a&gt;, &lt;a href=&quot;https://github.com/ZevEisenberg&quot;&gt;@ZevEisenberg&lt;/a&gt;, and &lt;a href=&quot;https://github.com/zmeyc&quot;&gt;@zmeyc&lt;/a&gt; for their contributions, help, and feedback on GRDB.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/aymerick&quot;&gt;@aymerick&lt;/a&gt; and &lt;a href=&quot;https://github.com/kali&quot;&gt;@kali&lt;/a&gt; because SQL.&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/ccgus/fmdb&quot;&gt;ccgus/fmdb&lt;/a&gt; for its excellency.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;hr /&gt; 
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/Provider/Style/URI&quot;&gt;URIs don&#39;t change: people change them.&lt;/a&gt;&lt;/p&gt; 
&lt;h4&gt;Adding support for missing SQL functions or operators&lt;/h4&gt; 
&lt;p&gt;This chapter was renamed to &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#embedding-sql-in-query-interface-requests&quot;&gt;Embedding SQL in Query Interface Requests&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Advanced DatabasePool&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;After Commit Hook&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/afternexttransaction(oncommit:onrollback:)&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Asynchronous APIs&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Changes Tracking&lt;/h4&gt; 
&lt;p&gt;This chapter has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#record-comparison&quot;&gt;Record Comparison&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Concurrency&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Custom Value Types&lt;/h4&gt; 
&lt;p&gt;Custom Value Types conform to the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasevalueconvertible&quot;&gt;&lt;code&gt;DatabaseValueConvertible&lt;/code&gt;&lt;/a&gt; protocol.&lt;/p&gt; 
&lt;h4&gt;Customized Decoding of Database Rows&lt;/h4&gt; 
&lt;p&gt;This chapter has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#beyond-fetchablerecord&quot;&gt;Beyond FetchableRecord&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Customizing the Persistence Methods&lt;/h4&gt; 
&lt;p&gt;This chapter was replaced with &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistence-callbacks&quot;&gt;Persistence Callbacks&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Database Changes Observation&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseobservation&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Database Configuration&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/configuration&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Database Queues&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasequeue&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Database Pools&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasepool&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Database Snapshots&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;DatabaseWriter and DatabaseReader Protocols&lt;/h4&gt; 
&lt;p&gt;This chapter was removed. See the references of &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasereader&quot;&gt;DatabaseReader&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasewriter&quot;&gt;DatabaseWriter&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Date and UUID Coding Strategies&lt;/h4&gt; 
&lt;p&gt;This chapter has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#data-date-and-uuid-coding-strategies&quot;&gt;Data, Date, and UUID Coding Strategies&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Dealing with External Connections&lt;/h4&gt; 
&lt;p&gt;This chapter has been superseded by the &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databasesharing&quot;&gt;Sharing a Database&lt;/a&gt; guide.&lt;/p&gt; 
&lt;h4&gt;Differences between Database Queues and Pools&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Enabling FTS5 Support&lt;/h4&gt; 
&lt;p&gt;FTS5 is enabled by default since GRDB 6.7.0.&lt;/p&gt; 
&lt;h4&gt;FetchedRecordsController&lt;/h4&gt; 
&lt;p&gt;FetchedRecordsController has been removed in GRDB 5.&lt;/p&gt; 
&lt;p&gt;The &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseobservation&quot;&gt;Database Observation&lt;/a&gt; chapter describes the other ways to observe the database.&lt;/p&gt; 
&lt;h4&gt;Full-Text Search&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/Documentation/FullTextSearch.md&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Guarantees and Rules&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Joined Queries Support&lt;/h4&gt; 
&lt;p&gt;This chapter was replaced with the documentation of &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/splittingrowadapters(columncounts:)&quot;&gt;splittingRowAdapters(columnCounts:)&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;List of Record Methods&lt;/h4&gt; 
&lt;p&gt;See &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/queryinterface&quot;&gt;Records and the Query Interface&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Migrations&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/migrations&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;NSNumber and NSDecimalNumber&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#nsnumber-nsdecimalnumber-and-decimal&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Persistable Protocol&lt;/h4&gt; 
&lt;p&gt;This protocol has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#persistablerecord-protocol&quot;&gt;PersistableRecord&lt;/a&gt; in GRDB 3.0.&lt;/p&gt; 
&lt;h4&gt;PersistenceError&lt;/h4&gt; 
&lt;p&gt;This error was renamed to &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#recorderror&quot;&gt;RecordError&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Prepared Statements&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/statement&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Record Class&lt;/h4&gt; 
&lt;p&gt;The &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/record&quot;&gt;&lt;code&gt;Record&lt;/code&gt;&lt;/a&gt; class is a legacy GRDB type. Since GRDB 7, it is not recommended to define record types by subclassing the &lt;code&gt;Record&lt;/code&gt; class.&lt;/p&gt; 
&lt;h4&gt;Row Adapters&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/rowadapter&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;RowConvertible Protocol&lt;/h4&gt; 
&lt;p&gt;This protocol has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#fetchablerecord-protocol&quot;&gt;FetchableRecord&lt;/a&gt; in GRDB 3.0.&lt;/p&gt; 
&lt;h4&gt;TableMapping Protocol&lt;/h4&gt; 
&lt;p&gt;This protocol has been renamed &lt;a href=&quot;https://raw.githubusercontent.com/groue/GRDB.swift/master/#tablerecord-protocol&quot;&gt;TableRecord&lt;/a&gt; in GRDB 3.0.&lt;/p&gt; 
&lt;h4&gt;Transactions and Savepoints&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/transactions&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Transaction Hook&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/database/afternexttransaction(oncommit:onrollback:)&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;TransactionObserver Protocol&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/transactionobserver&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;Unsafe Concurrency APIs&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/concurrency&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;ValueObservation&lt;/h4&gt; 
&lt;p&gt;This chapter has &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/valueobservation&quot;&gt;moved&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;ValueObservation and DatabaseRegionObservation&lt;/h4&gt; 
&lt;p&gt;This chapter has been superseded by &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/valueobservation&quot;&gt;ValueObservation&lt;/a&gt; and &lt;a href=&quot;https://swiftpackageindex.com/groue/GRDB.swift/documentation/grdb/databaseregionobservation&quot;&gt;DatabaseRegionObservation&lt;/a&gt;.&lt;/p&gt;</description>
      
      <media:content url="https://repository-images.githubusercontent.com/38304949/85814480-18da-11ea-964d-b51f40c421e5" medium="image" />
      
    </item>
    
    <item>
      <title>pluk-inc/markdown-preview</title>
      <link>https://github.com/pluk-inc/markdown-preview</link>
      <description>&lt;p&gt;A simple Markdown viewer for reading .md files&lt;/p&gt;&lt;hr&gt;&lt;h1 align=&quot;center&quot;&gt;Markdown Preview&lt;/h1&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/markdown-logo.svg?sanitize=true&quot; width=&quot;128&quot; alt=&quot;Markdown Preview logo&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; A fast, native macOS app for reading Markdown files. &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt;&lt;img alt=&quot;Platform&quot; src=&quot;https://img.shields.io/badge/platform-macOS%2015%2B-blue&quot; /&gt;&amp;nbsp;&lt;img alt=&quot;Swift&quot; src=&quot;https://img.shields.io/badge/swift-6.0-orange&quot; /&gt;&amp;nbsp;&lt;img alt=&quot;License&quot; src=&quot;https://img.shields.io/badge/license-MIT-green&quot; /&gt;&amp;nbsp;&lt;img alt=&quot;Latest release&quot; src=&quot;https://img.shields.io/github/v/release/pluk-inc/markdown-preview&quot; /&gt;&amp;nbsp;&lt;img alt=&quot;Homebrew cask&quot; src=&quot;https://img.shields.io/homebrew/cask/v/markdown-preview&quot; /&gt;&lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://buymeacoffee.com/pluk&quot;&gt; &lt;img src=&quot;https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png&quot; height=&quot;42&quot; alt=&quot;Buy Me a Coffee&quot; /&gt; &lt;/a&gt; &lt;/p&gt; 
&lt;hr /&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;Drop a &lt;code&gt;.md&lt;/code&gt; on the icon (or set Markdown Preview as your default handler) and get a clean, scrollable preview with a real document outline — no Electron, no browser tab.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Installation&lt;/h2&gt; 
&lt;p&gt;Markdown Preview is available in the official &lt;a href=&quot;https://formulae.brew.sh/cask/markdown-preview&quot;&gt;Homebrew cask repository&lt;/a&gt;:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install --cask markdown-preview
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Or grab the latest signed and notarized DMG from the &lt;a href=&quot;https://github.com/pluk-inc/markdown-preview/releases&quot;&gt;Releases&lt;/a&gt; page.&lt;/p&gt; 
&lt;h2&gt;Screenshots&lt;/h2&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/screenshot-main.png&quot; width=&quot;820&quot; alt=&quot;Main window with document outline sidebar&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;em&gt;Edit Markdown directly with a native formatting toolbar:&lt;/em&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/screenshot-edit-mode.png&quot; width=&quot;820&quot; alt=&quot;Edit Mode with document outline and Markdown formatting toolbar&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;em&gt;Quick Look preview — spacebar a &lt;code&gt;.md&lt;/code&gt; in Finder:&lt;/em&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/screenshot-quicklook.png&quot; width=&quot;640&quot; alt=&quot;Quick Look preview from Finder&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;em&gt;Customize the toolbar — drag in Print, Copy, Zoom and the rest from &lt;em&gt;View → Customize Toolbar…&lt;/em&gt;&lt;/em&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/screenshot-toolbar-customize.png&quot; width=&quot;820&quot; alt=&quot;Native macOS toolbar customization sheet showing draggable items&quot; /&gt; &lt;/p&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Native rendering&lt;/strong&gt; — &lt;code&gt;WKWebView&lt;/code&gt; pipeline backed by &lt;a href=&quot;https://github.com/swiftlang/swift-markdown&quot;&gt;swift-markdown&lt;/a&gt;, with heading anchors and link handling.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Edit Mode&lt;/strong&gt; — edit Markdown in place with a formatting toolbar for headings, emphasis, lists, quotes, code, and links. Toggle it from the toolbar or with &lt;kbd&gt;⌘E&lt;/kbd&gt;, then save with &lt;kbd&gt;⌘S&lt;/kbd&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Mermaid diagrams&lt;/strong&gt; — fenced &lt;code&gt;mermaid&lt;/code&gt; code blocks render as diagrams in both the app and Quick Look previews, using a bundled renderer so previews work offline without a CDN request.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Math equations&lt;/strong&gt; — LaTeX inline (&lt;code&gt;$x_1 + x_2$&lt;/code&gt;), display (&lt;code&gt;$$\int_0^1 x^2\,dx$$&lt;/code&gt;), and fenced &lt;code&gt;math&lt;/code&gt; blocks render with a bundled KaTeX. Selecting a rendered formula and copying yields the original LaTeX source (via the official &lt;code&gt;copy-tex&lt;/code&gt; extension).&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Document outline&lt;/strong&gt; — sidebar TOC that mirrors your headings; click to jump.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Inspector panel&lt;/strong&gt; — toggleable side panel with file metadata.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;In-document search&lt;/strong&gt; — toolbar search field plus standard &lt;kbd&gt;⌘F&lt;/kbd&gt; / &lt;kbd&gt;⌘G&lt;/kbd&gt; / &lt;kbd&gt;⌘⇧G&lt;/kbd&gt; for next/previous match.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Open With&lt;/strong&gt; — switch to your real editor (VS Code, Cursor, Zed, Sublime, BBEdit, Nova, CotEditor, TextMate, MacVim, Xcode, TextEdit) without leaving the preview. The list filters to apps that actually declare an editor role for Markdown, and remembers your pick.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Open in LLM&lt;/strong&gt; — send the current Markdown file to Codex, Claude, or ChatGPT from the toolbar. Supported apps open with file or folder context where possible, with a copy-and-open fallback for longer prompts.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Text zoom&lt;/strong&gt; — bump preview text up or down with trackpad pinch, the toolbar&#39;s &lt;kbd&gt;A A&lt;/kbd&gt; control, or &lt;kbd&gt;⌘+&lt;/kbd&gt; / &lt;kbd&gt;⌘−&lt;/kbd&gt; / &lt;kbd&gt;⌘0&lt;/kbd&gt;. Discrete Safari-style stops from 50% to 300%.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Customizable toolbar&lt;/strong&gt; — drag in the items you actually use (Print, Copy, Zoom, Sidebar, Open With, Inspector, Share, Search) via &lt;em&gt;View → Customize Toolbar…&lt;/em&gt; Standard AppKit affordance, your layout sticks across launches.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Share = copy the source&lt;/strong&gt; — the share toolbar feeds the picker the Markdown text itself, so &lt;strong&gt;Copy&lt;/strong&gt; writes the raw source to the clipboard (great for pasting into ChatGPT / Claude), and Mail, Messages, and Notes get the content in the body instead of a file URL.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Quick Look extension&lt;/strong&gt; — system-wide &lt;code&gt;.md&lt;/code&gt; previews from Finder spacebar, Spotlight, and Mail attachments without launching the app.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Command line tools&lt;/strong&gt; — install &lt;code&gt;mdp&lt;/code&gt;, &lt;code&gt;md-preview&lt;/code&gt;, and &lt;code&gt;markdown-preview&lt;/code&gt; from the app menu, then open files or folders from any shell with commands like &lt;code&gt;mdp README.md&lt;/code&gt; or &lt;code&gt;mdp .&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Default handler&lt;/strong&gt; — offers to register itself as the default &lt;code&gt;.md&lt;/code&gt; opener on first launch.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Supported file types&lt;/h2&gt; 
&lt;p&gt;&lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.markdown&lt;/code&gt;, &lt;code&gt;.mdown&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt; UTI: &lt;code&gt;net.daringfireball.markdown&lt;/code&gt;&lt;/p&gt; 
&lt;h2&gt;Requirements&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;macOS 15 or later&lt;/li&gt; 
 &lt;li&gt;Apple Silicon or Intel&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Building from source&lt;/h2&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git clone git@github.com:pluk-inc/markdown-preview.git
cd markdown-preview
open markdown-preview.xcodeproj
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Build and run the &lt;code&gt;markdown-preview&lt;/code&gt; scheme. Swift Package Manager will resolve &lt;a href=&quot;https://github.com/sparkle-project/Sparkle&quot;&gt;Sparkle&lt;/a&gt;, &lt;a href=&quot;https://github.com/getsentry/sentry-cocoa&quot;&gt;Sentry&lt;/a&gt;, and &lt;a href=&quot;https://github.com/swiftlang/swift-markdown&quot;&gt;swift-markdown&lt;/a&gt; on first build.&lt;/p&gt; 
&lt;h3&gt;Crash reporting&lt;/h3&gt; 
&lt;p&gt;Release builds submit native crash reports to the &lt;code&gt;pluk-inc/markdown-preview&lt;/code&gt; Sentry project. The integration does not collect performance traces, session data, breadcrumbs, network requests, user information, document contents, or file paths. Users can turn reporting off directly from Markdown Preview &amp;gt; Send Anonymous Crash Reports; on later launches, the Sentry SDK will not initialize at all.&lt;/p&gt; 
&lt;p&gt;The committed DSN is a public client key. Release archives upload the app dSYM with &lt;code&gt;sentry-cli&lt;/code&gt;; authenticate locally with &lt;code&gt;sentry-cli login&lt;/code&gt; and keep that authentication token outside the repository.&lt;/p&gt; 
&lt;h2&gt;Project layout&lt;/h2&gt; 
&lt;pre&gt;&lt;code&gt;md-preview/         Main app target (AppKit, WKWebView)
quick-look/         Quick Look extension (.appex)
scripts/            Release &amp;amp; rollback automation
Version.xcconfig    Marketing &amp;amp; build version (single source of truth)
appcast.xml         Sparkle update feed
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;Releasing&lt;/h2&gt; 
&lt;p&gt;Releases are driven by &lt;a href=&quot;http://amore.computer/&quot;&gt;Amore&lt;/a&gt; — it handles building, code signing, notarization, DMG creation, S3 upload, and Sparkle appcast publishing in one shot.&lt;/p&gt; 
&lt;p&gt;Bump &lt;code&gt;MARKETING_VERSION&lt;/code&gt; and &lt;code&gt;CURRENT_PROJECT_VERSION&lt;/code&gt; in &lt;code&gt;Version.xcconfig&lt;/code&gt;, then:&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;./scripts/release.sh
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Use &lt;code&gt;./scripts/rollback-release.sh&lt;/code&gt; to revert the appcast pointer if a release misbehaves.&lt;/p&gt; 
&lt;h2&gt;Contributing&lt;/h2&gt; 
&lt;p&gt;Pull requests are welcome. For larger changes, please open an issue first to discuss what you&#39;d like to change.&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;Fork the repo and create your branch from &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;Run the app and verify the change end-to-end (UI changes need a manual smoke test — there&#39;s no UI test suite yet).&lt;/li&gt; 
 &lt;li&gt;Keep PRs focused; one logical change per PR.&lt;/li&gt; 
 &lt;li&gt;Match the existing Swift style (no formatter is enforced; mirror nearby code).&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 align=&quot;center&quot; style=&quot;color: #8a8a8a;&quot;&gt;Special Sponsor&lt;/h2&gt; 
&lt;br /&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://pluk.sh&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/sponsors/pluk-logo.png&quot; height=&quot;54&quot; alt=&quot;Pluk&quot; /&gt; &lt;/a&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;https://amore.computer&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/docs/sponsors/amore-logo.png&quot; height=&quot;54&quot; alt=&quot;Amore&quot; /&gt; &lt;/a&gt; &lt;/p&gt; 
&lt;h2&gt;Support&lt;/h2&gt; 
&lt;p&gt;Markdown Preview is free and MIT-licensed. If it saved you a browser tab, you can &lt;a href=&quot;https://buymeacoffee.com/pluk&quot;&gt;buy us a coffee&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Acknowledgments&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;http://amore.computer/&quot;&gt;Amore&lt;/a&gt; — MacOS release automation (signing, notarization, DMG, hosting, appcast)&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-markdown&quot;&gt;swift-markdown&lt;/a&gt; — Markdown parser (Apple, cmark-gfm-backed)&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://mermaid.js.org/&quot;&gt;Mermaid&lt;/a&gt; — Bundled diagram renderer for &lt;code&gt;mermaid&lt;/code&gt; fenced code blocks&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://katex.org/&quot;&gt;KaTeX&lt;/a&gt; — Bundled math typesetter for inline &lt;code&gt;$…$&lt;/code&gt;, display &lt;code&gt;$$…$$&lt;/code&gt;, and &lt;code&gt;```math&lt;/code&gt; blocks&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://sparkle-project.org&quot;&gt;Sparkle&lt;/a&gt; — Auto-update framework&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://sentry.io&quot;&gt;Sentry&lt;/a&gt; — Privacy-filtered native crash reporting&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://lottiefiles.com/&quot;&gt;LottieFiles&lt;/a&gt; — Animated README logo&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/pluk-inc/markdown-preview/main/LICENSE&quot;&gt;MIT&lt;/a&gt;&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/5f7e6c57bff0250e3edabac0499be3b2fb63ed4a8b9e258da5ab045dc9a91dc8/pluk-inc/markdown-preview" medium="image" />
      
    </item>
    
    <item>
      <title>alienator88/Pearcleaner</title>
      <link>https://github.com/alienator88/Pearcleaner</link>
      <description>&lt;p&gt;A free, source-available and fair-code licensed mac app cleaner&lt;/p&gt;&lt;hr&gt;&lt;h1&gt;Pearcleaner&lt;/h1&gt; 
&lt;h3&gt;Website&lt;/h3&gt; 
&lt;p&gt;The only legitimate website owned by me is &lt;a href=&quot;https://itsalin.com&quot;&gt;https://itsalin.com&lt;/a&gt;. Anything else offering Pearcleaner downloads is either a scam or not affiliated with me. More details &lt;a href=&quot;https://www.reddit.com/r/macapps/comments/1ucstzy/psa_pearcleanercom_is_a_fake_site_pushing_macos/&quot;&gt;HERE&lt;/a&gt;.&lt;/p&gt; 
&lt;h3&gt;Project Status: On Hold&lt;/h3&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;As you may have noticed, development on the app has basically stopped since end of 2025, so I wanted to provide some context.&lt;/p&gt; 
 &lt;p&gt;Between a new job, joining a friend who is building a SaaS company, and other life priorities, I no longer have the time needed to actively maintain or continue development on the project.&lt;/p&gt; 
 &lt;p&gt;Another major reason is that I previously relied on my work MacBook for development. After changing jobs, I no longer have access to a Mac device that I can use for personal development work, which means I’m currently unable to build, test, or release updates for the app.&lt;/p&gt; 
 &lt;p&gt;Because of that, issue responses, feature work, PR reviews, and new releases are effectively on hold indefinitely for now.&lt;/p&gt; 
 &lt;p&gt;The project is not abandoned entirely, and I’d still like to return to it someday if circumstances change. For now though, I want to be transparent that active development is no longer possible on my end.&lt;/p&gt; 
 &lt;p&gt;Thank you to everyone who has used the app, reported issues, submitted ideas, or contributed. I genuinely appreciate all of the support the project has received.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;br /&gt; 
&lt;p align=&quot;center&quot;&gt; 
 &lt;!--    &lt;img src=&quot;https://github.com/alienator88/Pearcleaner/assets/91337119/165f6961-f4fc-4199-bc68-580bacff6eaf&quot; align=&quot;center&quot; width=&quot;128&quot; height=&quot;128&quot; /&gt; --&gt; &lt;img src=&quot;https://github.com/user-attachments/assets/62cd5fcb-92d3-4d3a-9664-161a7deabd46&quot; align=&quot;center&quot; width=&quot;160&quot; height=&quot;160&quot; /&gt; &lt;br /&gt; &lt;strong&gt;Status: &lt;/strong&gt;On Hold &lt;br /&gt; &lt;strong&gt;Version: &lt;/strong&gt;5.4.3 &lt;br /&gt; &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/releases&quot;&gt;&lt;strong&gt;Download&lt;/strong&gt;&lt;/a&gt; · &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/commits&quot;&gt;Commits&lt;/a&gt; &lt;/p&gt; 
&lt;p&gt;&lt;/p&gt; 
&lt;br /&gt; 
&lt;p&gt;A free, source-available and fair-code licensed Mac app cleaner inspired by &lt;a href=&quot;https://freemacsoft.net/appcleaner/&quot;&gt;Freemacsoft&#39;s AppCleaner&lt;/a&gt; and &lt;a href=&quot;https://github.com/sunknudsen/guides/tree/main/archive/how-to-clean-uninstall-macos-apps-using-appcleaner-open-source-alternative&quot;&gt;Sun Knudsen&#39;s Privacy Guides&lt;/a&gt; post on his app-cleaner script. This project was born out of wanting to learn more on how macOS deals with app installation/uninstallation and getting more Swift experience. If you have suggestions I&#39;m open to hearing them, submit a feature request!&lt;/p&gt; 
&lt;h3&gt;Table of Contents:&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#features&quot;&gt;Features&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#screenshots&quot;&gt;Screenshots&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#issues&quot;&gt;Issues&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#requirements&quot;&gt;Requirements&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#getting-pearcleaner&quot;&gt;Download&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#translations&quot;&gt;Translations&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#license&quot;&gt;License&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#thanks&quot;&gt;Thanks&lt;/a&gt; | &lt;a href=&quot;https://raw.githubusercontent.com/alienator88/Pearcleaner/main/#other-apps&quot;&gt;Other Apps&lt;/a&gt;&lt;/p&gt; 
&lt;br /&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;h3&gt;Core&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;App Uninstall • Orphaned File Search • Development Environment Manager • File Search • Homebrew Manager • App Lipo • PKG Manager • Plugin Manager • Services Manager • Apps Updater&lt;/strong&gt;&lt;/li&gt; 
 &lt;li&gt;Drag/drop apps, CLI support, and deep link automation &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/wiki/Deep-Link-Guide&quot;&gt;view&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;List or Grid view with badges for web/iOS apps&lt;/li&gt; 
 &lt;li&gt;Finder Extension for right-click uninstall&lt;/li&gt; 
 &lt;li&gt;Pearcleaner self-uninstall and other options&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Utilities&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Prune unused app translations, keeping only preferred languages&lt;/li&gt; 
 &lt;li&gt;Strip unneeded architectures from universal apps without requirement of lipo binary from xcode tools&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Sentinel Monitor&lt;/strong&gt;: Automatic cleanup when apps hit Trash (~2MB RAM)&lt;/li&gt; 
 &lt;li&gt;Export app bundles and file lists&lt;/li&gt; 
 &lt;li&gt;Basic Steam games support&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3&gt;Customization&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Theme system with custom colors&lt;/li&gt; 
 &lt;li&gt;Include/exclude directories for searching&lt;/li&gt; 
 &lt;li&gt;Adjustable search sensitivity&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Screenshots&lt;/h2&gt; 
&lt;img src=&quot;https://github.com/user-attachments/assets/5095d30c-3665-4b24-bf00-756baac59026&quot; align=&quot;left&quot; width=&quot;400&quot; /&gt; 
&lt;img src=&quot;https://github.com/user-attachments/assets/e9841914-613e-4206-b0bd-07963bf27507&quot; align=&quot;center&quot; width=&quot;400&quot; /&gt; 
&lt;p&gt;&lt;/p&gt; 
&lt;img src=&quot;https://github.com/user-attachments/assets/c35258c2-2886-412c-a4c4-3c5e343e7a2c&quot; align=&quot;left&quot; width=&quot;400&quot; /&gt; 
&lt;img src=&quot;https://github.com/user-attachments/assets/e6253ce4-b1e4-4851-a2c2-46b1f1e128cb&quot; align=&quot;center&quot; width=&quot;400&quot; /&gt; 
&lt;h2&gt;Issues&lt;/h2&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-warning&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-alert mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Warning&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;When submitting issues, please use the appropriate issue template corresponding with your problem &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/issues/new/choose&quot;&gt;HERE&lt;/a&gt;&lt;/li&gt; 
  &lt;li&gt;Issues with no template will be closed&lt;/li&gt; 
  &lt;li&gt;This is a personal/hobby app, therefore the project is fairly opinionated. Opinion-based requests (e.g., “the layout would look better this way”) will not be considered.&lt;/li&gt; 
 &lt;/ul&gt; 
&lt;/div&gt; 
&lt;h2&gt;Requirements&lt;/h2&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Note&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;Full Disk permission to search for files&lt;/li&gt; 
  &lt;li&gt;Privileged Helper to perform actions on system folders&lt;/li&gt; 
 &lt;/ul&gt; 
&lt;/div&gt; 
&lt;table&gt; 
 &lt;thead&gt; 
  &lt;tr&gt; 
   &lt;th&gt;macOS Version&lt;/th&gt; 
   &lt;th&gt;Codename&lt;/th&gt; 
   &lt;th&gt;Supported&lt;/th&gt; 
  &lt;/tr&gt; 
 &lt;/thead&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;13.x&lt;/td&gt; 
   &lt;td&gt;Ventura&lt;/td&gt; 
   &lt;td&gt;✅&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;14.x&lt;/td&gt; 
   &lt;td&gt;Sonoma&lt;/td&gt; 
   &lt;td&gt;✅&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;15.x&lt;/td&gt; 
   &lt;td&gt;Sequoia&lt;/td&gt; 
   &lt;td&gt;✅&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;26.x&lt;/td&gt; 
   &lt;td&gt;Tahoe&lt;/td&gt; 
   &lt;td&gt;✅&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;TBD&lt;/td&gt; 
   &lt;td&gt;Beta&lt;/td&gt; 
   &lt;td&gt;❌&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;blockquote&gt; 
 &lt;p&gt;Versions prior to macOS 13.0 are not supported due to missing Swift/SwiftUI APIs required by the app.&lt;/p&gt; 
&lt;/blockquote&gt; 
&lt;h2&gt;Getting Pearcleaner&lt;/h2&gt; 
&lt;details&gt; 
 &lt;summary&gt;Releases&lt;/summary&gt; 
 &lt;p&gt;Pre-compiled, always up-to-date versions are available from my &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/releases&quot;&gt;releases&lt;/a&gt; page.&lt;/p&gt; 
&lt;/details&gt; 
&lt;details&gt; 
 &lt;summary&gt;Homebrew&lt;/summary&gt; 
 &lt;p&gt;You can add the app via Homebrew:&lt;/p&gt; 
 &lt;pre&gt;&lt;code&gt;brew install --cask pearcleaner
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;h2&gt;Translations&lt;/h2&gt; 
&lt;p&gt;If you are able to contribute to translations for the app, please see this discussion: &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/discussions/137&quot;&gt;https://github.com/alienator88/Pearcleaner/discussions/137&lt;/a&gt;&lt;/p&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;
 &lt;p class=&quot;markdown-alert-title&quot;&gt;
  &lt;svg class=&quot;octicon octicon-report mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;
   &lt;path d=&quot;M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;Important&lt;/p&gt;
 &lt;p&gt;Pearcleaner is licensed under Apache 2.0 with &lt;a href=&quot;https://commonsclause.com/&quot;&gt;Commons Clause&lt;/a&gt;. This means that you can do anything you&#39;d like with the source, modify it, contribute to it, etc., but the license explicitly prohibits any form of monetization for Pearcleaner or any modified versions of it. See full license &lt;a href=&quot;https://github.com/alienator88/Pearcleaner/raw/main/LICENSE.md&quot;&gt;HERE&lt;/a&gt;&lt;/p&gt; 
&lt;/div&gt; 
&lt;h2&gt;Thanks&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Much appreciation to &lt;a href=&quot;https://freemacsoft.net/appcleaner/&quot;&gt;Freemacsoft&#39;s AppCleaner&lt;/a&gt; and &lt;a href=&quot;https://github.com/sunknudsen/guides/tree/main/archive/how-to-clean-uninstall-macos-apps-using-appcleaner-open-source-alternative&quot;&gt;Sun Knudsen&#39;s app-cleaner script&lt;/a&gt; for the inspiration&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/dharsanb&quot;&gt;DharsanB&lt;/a&gt; for sponsoring my Apple Developer account&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Some of my apps&lt;/h2&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/alienator88/Pearcleaner&quot;&gt;Pearcleaner&lt;/a&gt; - An opensource app cleaner with privacy in mind&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/alienator88/Sentinel&quot;&gt;Sentinel&lt;/a&gt; - A GUI for controlling gatekeeper status on your Mac&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/alienator88/Viz&quot;&gt;Viz&lt;/a&gt; - Utility for extracting text from images, videos, qr/barcodes&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/alienator88/PearHID&quot;&gt;PearHID&lt;/a&gt; - Remap your macOS keyboard with a simple SwiftUI frontend&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/116412ab5a446c74229354f216734a087728292924765a3780e42a46fe336cde/alienator88/Pearcleaner" medium="image" />
      
    </item>
    
    <item>
      <title>ChartsOrg/Charts</title>
      <link>https://github.com/ChartsOrg/Charts</link>
      <description>&lt;p&gt;Beautiful charts for iOS/tvOS/OSX! The Apple side of the crossplatform MPAndroidChart.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;strong&gt;Version 4.0.0&lt;/strong&gt;, synced to &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart/commit/f6a398b&quot;&gt;MPAndroidChart #f6a398b&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/ChartsOrg/Charts/master/Assets/feature_graphic.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://github.com/ChartsOrg/Charts/actions/workflows/build.yml&quot;&gt;&lt;img src=&quot;https://github.com/ChartsOrg/Charts/actions/workflows/build.yml/badge.svg?sanitize=true&quot; alt=&quot;Build&quot; /&gt;&lt;/a&gt; &lt;img src=&quot;https://img.shields.io/cocoapods/p/Charts.svg?sanitize=true&quot; alt=&quot;Supported Platforms&quot; /&gt; &lt;a href=&quot;https://github.com/ChartsOrg/Charts/releases&quot;&gt;&lt;img src=&quot;https://img.shields.io/github/release/ChartsOrg/Charts.svg?sanitize=true&quot; alt=&quot;Releases&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://cocoapods.org/pods/charts&quot;&gt;&lt;img src=&quot;https://img.shields.io/cocoapods/v/Charts.svg?sanitize=true&quot; alt=&quot;Latest pod release&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/Carthage/Carthage&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat&quot; alt=&quot;Carthage compatible&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;h3&gt;Just a heads up: Charts 5.0 has some breaking changes. Charts has now been renamed DGCharts to prevent conflicts with Apple&#39;s new Swift Charts. Please read &lt;a href=&quot;https://github.com/ChartsOrg/Charts/releases/tag/5.0.0&quot;&gt;the release/migration notes&lt;/a&gt;.&lt;/h3&gt; 
&lt;h3&gt;One more heads up: As Swift evolves, if you are not using the latest Swift compiler, you shouldn&#39;t check out the master branch. Instead, you should go to the release page and pick up whatever suits you.&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;Xcode 14 / Swift 5.7 (master branch)&lt;/li&gt; 
 &lt;li&gt;iOS &amp;gt;= 12.0 (Use as an &lt;strong&gt;Embedded&lt;/strong&gt; Framework)&lt;/li&gt; 
 &lt;li&gt;tvOS &amp;gt;= 12.0&lt;/li&gt; 
 &lt;li&gt;macOS &amp;gt;= 10.13&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Okay so there&#39;s this beautiful library called &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart&quot;&gt;MPAndroidChart&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/philippjahoda&quot;&gt;Philipp Jahoda&lt;/a&gt; which has become very popular amongst Android developers, but there was no decent solution to create charts for iOS.&lt;/p&gt; 
&lt;p&gt;I&#39;ve chosen to write it in &lt;code&gt;Swift&lt;/code&gt; as it can be highly optimized by the compiler, and can be used in both &lt;code&gt;Swift&lt;/code&gt; and &lt;code&gt;ObjC&lt;/code&gt; project. The demo project is written in &lt;code&gt;ObjC&lt;/code&gt; to demonstrate how it works.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;An amazing feature&lt;/strong&gt; of this library now, for Android, iOS, tvOS and macOS, is the time it saves you when developing for both platforms, as the learning curve is singleton- it happens only once, and the code stays very similar so developers don&#39;t have to go around and re-invent the app to produce the same output with a different library. (And that&#39;s not even considering the fact that there&#39;s not really another good choice out there currently...)&lt;/p&gt; 
&lt;h2&gt;Having trouble running the demo?&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;ChartsDemo/ChartsDemo.xcodeproj&lt;/code&gt; is the demo project for iOS/tvOS&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;ChartsDemo-OSX/ChartsDemo-OSX.xcodeproj&lt;/code&gt; is the demo project for macOS&lt;/li&gt; 
 &lt;li&gt;Make sure you are running a supported version of Xcode. 
  &lt;ul&gt; 
   &lt;li&gt;Usually it is specified here a few lines above.&lt;/li&gt; 
   &lt;li&gt;In most cases it will be the latest Xcode version.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;Make sure that your project supports Swift 5.0&lt;/li&gt; 
 &lt;li&gt;Optional: Run &lt;code&gt;carthage checkout&lt;/code&gt; in the project folder, to fetch dependencies (i.e testing dependencies). 
  &lt;ul&gt; 
   &lt;li&gt;If you don&#39;t have Carthage - you can get it &lt;a href=&quot;https://github.com/Carthage/Carthage/releases&quot;&gt;here&lt;/a&gt;.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Usage&lt;/h2&gt; 
&lt;p&gt;In order to correctly compile:&lt;/p&gt; 
&lt;ol&gt; 
 &lt;li&gt;Drag the &lt;code&gt;DGCharts.xcodeproj&lt;/code&gt; to your project&lt;/li&gt; 
 &lt;li&gt;Go to your target&#39;s settings, hit the &quot;+&quot; under the &quot;Frameworks, Libraries, and Embedded Content&quot; section, and select the DGCharts.framework&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;@import DGCharts&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;When using Swift in an ObjC project:&lt;/li&gt; 
&lt;/ol&gt; 
&lt;ul&gt; 
 &lt;li&gt;You need to import your Bridging Header. Usually it is &quot;&lt;em&gt;YourProject-Swift.h&lt;/em&gt;&quot;, so in ChartsDemo it&#39;s &quot;&lt;em&gt;ChartsDemo-Swift.h&lt;/em&gt;&quot;. Do not try to actually include &quot;&lt;em&gt;ChartsDemo-Swift.h&lt;/em&gt;&quot; in your project 😃&lt;/li&gt; 
 &lt;li&gt;(Xcode 8.1 and earlier) Under &quot;Build Options&quot;, mark &quot;Embedded Content Contains Swift Code&quot;&lt;/li&gt; 
 &lt;li&gt;(Xcode 8.2+) Under &quot;Build Options&quot;, mark &quot;Always Embed Swift Standard Libraries&quot;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;ol start=&quot;5&quot;&gt; 
 &lt;li&gt;When using &lt;a href=&quot;https://realm.io/&quot;&gt;Realm.io&lt;/a&gt;: 
  &lt;ul&gt; 
   &lt;li&gt;Note that the Realm framework is not linked with Charts - it is only there for &lt;em&gt;optional&lt;/em&gt; bindings. Which means that you need to have the framework in your project, and in a compatible version to whatever is compiled with DGCharts. We will do our best to always compile against the latest version.&lt;/li&gt; 
   &lt;li&gt;You&#39;ll need to add &lt;code&gt;ChartsRealm&lt;/code&gt; as a dependency too.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2&gt;3rd party tutorials&lt;/h2&gt; 
&lt;h4&gt;Video tutorials&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mWhwe_tLNE8&amp;amp;list=PL_csAAO9PQ8bjzg-wxEff1Fr0Y5W1hrum&amp;amp;index=5&quot;&gt;Chart in Swift - Setting Up a Basic Line Chart Using iOS Charts(Alex Nagy)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://youtu.be/csd7pyfEXgw&quot;&gt;Charts Framework in SwiftUI - Bar Chart (Stewart Lynch)&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Blog posts&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@skoli/using-realm-and-charts-with-swift-3-in-ios-10-40c42e3838c0#.2gyymwfh8&quot;&gt;Using Realm and Charts with Swift 3 in iOS 10 (Sami Korpela)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@OsianSmith/creating-a-line-chart-in-swift-3-and-ios-10-2f647c95392e&quot;&gt;Creating a Line Chart in Swift 3 and iOS 10 (Osian Smith)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://github.com/annalizhaz/ChartsForSwiftBasic&quot;&gt;Beginning Set-up and Example Using Charts with Swift 3&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@HeyDaveTheDev/creating-a-radar-chart-in-swift-5791afcf92f0&quot;&gt;Creating a Radar Chart in Swift (David Piper)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@zzzzbh/plotting-in-ios-using-charts-framework-with-swiftui-222034a2bea6&quot;&gt;Plotting in IOS using Charts framework with SwiftUI (Evgeny Basisty)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@penny-huang/swift-setting-up-a-basic-bar-chart-using-ios-charts-afd6aad96ac&quot;&gt;Set Up a Basic Bar Chart Using iOS-Charts (Penny Huang)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/@penny-huang/swift-ios-charts-tutorial-highlight-selected-value-with-a-custom-marker-30ccbf92aa1b&quot;&gt;iOS-Charts Tutorial: Highlight Selected Value With a Custom Marker (Penny Huang)&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://medium.com/better-programming/drawing-charts-in-ios-before-swiftui-9f95b8612607&quot;&gt;Drawing Charts in iOS Before SwiftUI (Gennady Stepanov)&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Want your tutorial to show here? Create a PR!&lt;/p&gt; 
&lt;h2&gt;Troubleshooting&lt;/h2&gt; 
&lt;h4&gt;Can&#39;t compile?&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;Please note the difference between installing a compiled framework from CocoaPods or Carthage, and copying the source code.&lt;/li&gt; 
 &lt;li&gt;Please read the &lt;strong&gt;Usage&lt;/strong&gt; section again.&lt;/li&gt; 
 &lt;li&gt;Search in the issues&lt;/li&gt; 
 &lt;li&gt;Try to politely ask in the issues section&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4&gt;Other problems / feature requests&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;Search in the issues&lt;/li&gt; 
 &lt;li&gt;Try to politely ask in the issues section&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;CocoaPods Install&lt;/h2&gt; 
&lt;p&gt;Add &lt;code&gt;pod &#39;DGCharts&#39;&lt;/code&gt; to your Podfile. &quot;DGCharts&quot; is the name of the library.&lt;br /&gt; For &lt;a href=&quot;https://realm.io/&quot;&gt;Realm&lt;/a&gt; support, please add &lt;code&gt;pod &#39;ChartsRealm&#39;&lt;/code&gt; too.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;s&gt;&lt;code&gt;pod &#39;ios-charts&#39;&lt;/code&gt;&lt;/s&gt; is not the correct library, and refers to a different project by someone else.&lt;/p&gt; 
&lt;h2&gt;Carthage Install&lt;/h2&gt; 
&lt;p&gt;DGCharts now include Carthage prebuilt binaries.&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-carthage&quot;&gt;github &quot;ChartsOrg/Charts&quot; == 5.1.0
github &quot;ChartsOrg/Charts&quot; ~&amp;gt; 5.1.0
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;In order to build the binaries for a new release, use &lt;code&gt;carthage build --no-skip-current &amp;amp;&amp;amp; carthage archive Charts&lt;/code&gt;.&lt;/p&gt; 
&lt;h2&gt;Swift Package Manager Install&lt;/h2&gt; 
&lt;p&gt;Swift Package Manager&lt;/p&gt; 
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;dependencies: [
    .package(url: &quot;https://github.com/ChartsOrg/Charts.git&quot;, .upToNextMajor(from: &quot;5.1.0&quot;))
]
&lt;/code&gt;&lt;/pre&gt; 
&lt;h2&gt;3rd party bindings&lt;/h2&gt; 
&lt;p&gt;Xamarin (by @Flash3001): &lt;em&gt;iOS&lt;/em&gt; - &lt;a href=&quot;https://github.com/Flash3001/iOSCharts.Xamarin&quot;&gt;GitHub&lt;/a&gt;/&lt;a href=&quot;https://www.nuget.org/packages/iOSCharts/&quot;&gt;NuGet&lt;/a&gt;. &lt;em&gt;Android&lt;/em&gt; - &lt;a href=&quot;https://github.com/Flash3001/MPAndroidChart.Xamarin&quot;&gt;GitHub&lt;/a&gt;/&lt;a href=&quot;https://www.nuget.org/packages/MPAndroidChart/&quot;&gt;NuGet&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Help&lt;/h2&gt; 
&lt;p&gt;If you like what you see here, and want to support the work being done in this repository, you could:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Contribute code, issues and pull requests&lt;/li&gt; 
 &lt;li&gt;Let people know this library exists (🔥 spread the word 🔥)&lt;/li&gt; 
 &lt;li&gt;&lt;a href=&quot;https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;amp;hosted_button_id=68UL6Y8KUPS96&quot;&gt;&lt;img src=&quot;https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif&quot; alt=&quot;Donate&quot; /&gt;&lt;/a&gt; (You can buy me a beer, or you can buy me dinner 😃&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The author of &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart&quot;&gt;MPAndroidChart&lt;/a&gt; is the reason that this library exists, and is accepting &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart#donations&quot;&gt;donations&lt;/a&gt; on his page. He deserves them!&lt;/p&gt; 
&lt;h2&gt;Questions &amp;amp; Issues&lt;/h2&gt; 
&lt;p&gt;If you are having questions or problems, you should:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Make sure you are using the latest version of the library. Check the &lt;a href=&quot;https://github.com/ChartsOrg/Charts/releases&quot;&gt;&lt;strong&gt;release-section&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Study the Android version&#39;s &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart/wiki&quot;&gt;&lt;strong&gt;Documentation-Wiki&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Search or open questions on &lt;a href=&quot;http://stackoverflow.com/questions/tagged/ios-charts&quot;&gt;&lt;strong&gt;stackoverflow&lt;/strong&gt;&lt;/a&gt; with the &lt;code&gt;ios-charts&lt;/code&gt; tag&lt;/li&gt; 
 &lt;li&gt;Search &lt;a href=&quot;https://github.com/ChartsOrg/Charts/issues&quot;&gt;&lt;strong&gt;known issues&lt;/strong&gt;&lt;/a&gt; for your problem (open and closed)&lt;/li&gt; 
 &lt;li&gt;Create new issues (please 🔥 &lt;strong&gt;search known issues before&lt;/strong&gt; 🔥, do not create duplicate issues)∏&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h1&gt;Features&lt;/h1&gt; 
&lt;p&gt;&lt;strong&gt;Core features:&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;8 different chart types&lt;/li&gt; 
 &lt;li&gt;Scaling on both axes (with touch-gesture, axes separately or pinch-zoom)&lt;/li&gt; 
 &lt;li&gt;Dragging / Panning (with touch-gesture)&lt;/li&gt; 
 &lt;li&gt;Combined-Charts (line-, bar-, scatter-, candle-stick-, bubble-)&lt;/li&gt; 
 &lt;li&gt;Dual (separate) Axes&lt;/li&gt; 
 &lt;li&gt;Customizable Axes (both x- and y-axis)&lt;/li&gt; 
 &lt;li&gt;Highlighting values (with customizable popup-views)&lt;/li&gt; 
 &lt;li&gt;Save chart to camera-roll / export to PNG/JPEG&lt;/li&gt; 
 &lt;li&gt;Predefined color templates&lt;/li&gt; 
 &lt;li&gt;Legends (generated automatically, customizable)&lt;/li&gt; 
 &lt;li&gt;Animations (build up animations, on both x- and y-axis)&lt;/li&gt; 
 &lt;li&gt;Limit lines (providing additional information, maximums, ...)&lt;/li&gt; 
 &lt;li&gt;Fully customizable (paints, typefaces, legends, colors, background, gestures, dashed lines, ...)&lt;/li&gt; 
 &lt;li&gt;Plotting data directly from &lt;a href=&quot;https://realm.io&quot;&gt;&lt;strong&gt;Realm.io&lt;/strong&gt;&lt;/a&gt; mobile database (&lt;a href=&quot;https://github.com/ChartsOrg/ChartsRealm&quot;&gt;here&lt;/a&gt;)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Chart types:&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&lt;em&gt;Screenshots are currently taken from the original repository, as they render exactly the same 😃&lt;/em&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;LineChart (with legend, simple design)&lt;/strong&gt; &lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart4.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;LineChart (with legend, simple design)&lt;/strong&gt; &lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart3.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;LineChart (cubic lines)&lt;/strong&gt; &lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/cubiclinechart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;LineChart (gradient fill)&lt;/strong&gt; &lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/line_chart_gradient.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;Combined-Chart (bar- and linechart in this case)&lt;/strong&gt; &lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/combined_chart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;BarChart (with legend, simple design)&lt;/strong&gt;&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_barchart3.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;BarChart (grouped DataSets)&lt;/strong&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/groupedbarchart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Horizontal-BarChart&lt;/strong&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPChart/master/screenshots/horizontal_barchart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;PieChart (with selection, ...)&lt;/strong&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/simpledesign_piechart1.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;ScatterChart&lt;/strong&gt; (with squares, triangles, circles, ... and more)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/scatterchart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;CandleStickChart&lt;/strong&gt; (for financial data)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/candlestickchart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;BubbleChart&lt;/strong&gt; (area covered by bubbles indicates the value)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/bubblechart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;RadarChart&lt;/strong&gt; (spider web chart)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/radarchart.png&quot; alt=&quot;alt tag&quot; /&gt;&lt;/p&gt; 
&lt;h1&gt;Documentation&lt;/h1&gt; 
&lt;p&gt;Currently there&#39;s no need for documentation for the iOS/tvOS/macOS version, as the API is &lt;strong&gt;95% the same&lt;/strong&gt; as on Android.&lt;br /&gt; You can read the official &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart&quot;&gt;MPAndroidChart&lt;/a&gt; documentation here: &lt;a href=&quot;https://github.com/PhilJay/MPAndroidChart/wiki&quot;&gt;&lt;strong&gt;Wiki&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;Or you can see the Charts Demo project in both Objective-C and Swift (&lt;a href=&quot;https://github.com/ChartsOrg/Charts/tree/master/ChartsDemo-iOS&quot;&gt;&lt;strong&gt;ChartsDemo-iOS&lt;/strong&gt;&lt;/a&gt;, as well as macOS &lt;a href=&quot;https://github.com/ChartsOrg/Charts/tree/master/ChartsDemo-macOS&quot;&gt;&lt;strong&gt;ChartsDemo-macOS&lt;/strong&gt;&lt;/a&gt;) and learn the how-tos from it.&lt;/p&gt; 
&lt;h1&gt;Special Thanks&lt;/h1&gt; 
&lt;p&gt;Goes to &lt;a href=&quot;https://github.com/liuxuan30&quot;&gt;@liuxuan30&lt;/a&gt;, &lt;a href=&quot;https://github.com/pmairoldi&quot;&gt;@pmairoldi&lt;/a&gt;, &lt;a href=&quot;https://github.com/jjatie&quot;&gt;@jjatie&lt;/a&gt; and &lt;a href=&quot;https://github.com/AlBirdie&quot;&gt;@AlBirdie&lt;/a&gt; for new features, bugfixes, and lots and lots of involvement in our open-sourced community! You guys are a huge help to all of those coming here with questions and issues, and I couldn&#39;t respond to all of those without you.&lt;/p&gt; 
&lt;h3&gt;Our amazing sponsors&lt;/h3&gt; 
&lt;p&gt;&lt;a href=&quot;https://debricked.com/&quot;&gt;Debricked&lt;/a&gt;: Use open source securely&lt;/p&gt; 
&lt;p&gt;&lt;a href=&quot;https://debricked.com/&quot;&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/4375169/73585544-25bfa800-44dd-11ea-9661-82519a125302.jpg&quot; alt=&quot;debricked&quot; /&gt;&lt;/a&gt;&lt;/p&gt; 
&lt;h1&gt;License&lt;/h1&gt; 
&lt;p&gt;Copyright 2016 Daniel Cohen Gindi &amp;amp; Philipp Jahoda&lt;/p&gt; 
&lt;p&gt;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License. You may obtain a copy of the License at&lt;/p&gt; 
&lt;pre&gt;&lt;code&gt;http://www.apache.org/licenses/LICENSE-2.0
&lt;/code&gt;&lt;/pre&gt; 
&lt;p&gt;Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/204c2889107b1696974de688df08b514b88802bc90573b2ebb4b3e6a971cf8a0/ChartsOrg/Charts" medium="image" />
      
    </item>
    
    <item>
      <title>zachlatta/freeflow</title>
      <link>https://github.com/zachlatta/freeflow</link>
      <description>&lt;p&gt;Free &amp; fast alternative to Wispr Flow&lt;/p&gt;&lt;hr&gt;&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/zachlatta/freeflow/main/Resources/AppIcon-Source.png&quot; width=&quot;128&quot; height=&quot;128&quot; alt=&quot;FreeFlow icon&quot; /&gt; &lt;/p&gt; 
&lt;h1 align=&quot;center&quot;&gt;FreeFlow&lt;/h1&gt; 
&lt;p align=&quot;center&quot;&gt; Free and open source alternative to &lt;a href=&quot;https://wisprflow.ai&quot;&gt;Wispr Flow&lt;/a&gt;, &lt;a href=&quot;https://superwhisper.com&quot;&gt;Superwhisper&lt;/a&gt;, and &lt;a href=&quot;https://monologue.to&quot;&gt;Monologue&lt;/a&gt;. &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;a href=&quot;https://github.com/zachlatta/freeflow/releases/latest/download/FreeFlow.dmg&quot;&gt;&lt;b&gt;⬇ Download FreeFlow.dmg&lt;/b&gt;&lt;/a&gt;&lt;br /&gt; &lt;sub&gt;Works on all Macs (Apple Silicon + Intel)&lt;/sub&gt; &lt;/p&gt; 
&lt;hr /&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;https://raw.githubusercontent.com/zachlatta/freeflow/main/Resources/demo.gif&quot; alt=&quot;FreeFlow demo&quot; width=&quot;600&quot; /&gt; &lt;/p&gt; 
&lt;p align=&quot;center&quot;&gt; &lt;i&gt;Thank you to &lt;a href=&quot;https://github.com/marcbodea&quot;&gt;@marcbodea&lt;/a&gt; for maintaining FreeFlow!&lt;/i&gt; &lt;/p&gt; 
&lt;h2&gt;Overview&lt;/h2&gt; 
&lt;p&gt;FreeFlow is a free Mac dictation app inspired by &lt;a href=&quot;https://wisprflow.ai/&quot;&gt;Wispr Flow&lt;/a&gt;, &lt;a href=&quot;https://superwhisper.com/&quot;&gt;Superwhisper&lt;/a&gt;, and &lt;a href=&quot;https://www.monologue.to/&quot;&gt;Monologue&lt;/a&gt;. It gives you fast AI transcription, context-aware cleanup, and voice-driven text editing without a monthly subscription.&lt;/p&gt; 
&lt;h2&gt;Quick Start&lt;/h2&gt; 
&lt;ol&gt; 
 &lt;li&gt;Download the app from above or &lt;a href=&quot;https://github.com/zachlatta/freeflow/releases/latest/download/FreeFlow.dmg&quot;&gt;click here&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Get a free Groq API key from &lt;a href=&quot;https://groq.com/&quot;&gt;groq.com&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Hold &lt;code&gt;Fn&lt;/code&gt; to talk, or tap &lt;code&gt;Command-Fn&lt;/code&gt; to start and stop dictation, and have whatever you say pasted into the current text field&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2&gt;Features&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Custom shortcuts:&lt;/strong&gt; Customize both hold-to-talk and toggle dictation shortcuts. If your toggle shortcut extends your hold shortcut, you can start in hold mode and press the extra modifier keys to latch into tap mode without stopping the recording.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Context-aware cleanup:&lt;/strong&gt; FreeFlow can read nearby app context so names, terms, and phrases are spelled correctly when you dictate into email, terminals, docs, and other apps.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Custom vocabulary:&lt;/strong&gt; Add names, jargon, and project-specific words that FreeFlow should preserve during cleanup.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;OpenAI-compatible providers:&lt;/strong&gt; Use Groq by default, or configure a custom model and API URL in settings.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Edit Mode&lt;/h2&gt; 
&lt;p&gt;Edit Mode lets you highlight existing text and transform it with a spoken instruction, like &quot;make this shorter&quot; or &quot;turn this into bullets.&quot; Enable it in settings, then use your normal dictation shortcut on selected text, or choose Manual mode to require an extra modifier key.&lt;/p&gt; 
&lt;h2&gt;Privacy&lt;/h2&gt; 
&lt;p&gt;There is no FreeFlow server, so FreeFlow does not store or retain your data. The only information that leaves your computer are API calls to your configured transcription and LLM provider.&lt;/p&gt; 
&lt;h2&gt;Custom Cleanup&lt;/h2&gt; 
&lt;p&gt;If you&#39;d rather keep cleanup more literal and less context-aware, you can paste this simpler prompt into the custom system prompt setting:&lt;/p&gt; 
&lt;details&gt; 
 &lt;summary&gt;Simple post-processing prompt&lt;/summary&gt; 
 &lt;pre&gt;&lt;code&gt;You are a dictation post-processor. You receive raw speech-to-text output and return clean text ready to be typed into an application.

Your job:
- Remove filler words (um, uh, you know, like) unless they carry meaning.
- Fix spelling, grammar, and punctuation errors.
- When the transcript already contains a word that is a close misspelling of a name or term from the context or custom vocabulary, correct the spelling. Never insert names or terms from context that the speaker did not say.
- Preserve the speaker&#39;s intent, tone, and meaning exactly.

Output rules:
- Return ONLY the cleaned transcript text, nothing else. So NEVER output words like &quot;Here is the cleaned transcript text:&quot;
- If the transcription is empty, return exactly: EMPTY
- Do not add words, names, or content that are not in the transcription. The context is only for correcting spelling of words already spoken.
- Do not change the meaning of what was said.

Example:
RAW_TRANSCRIPTION: &quot;hey um so i just wanted to like follow up on the meating from yesterday i think we should definately move the dedline to next friday becuz the desine team still needs more time to finish the mock ups and um yeah let me know if that works for you ok thanks&quot;

Then your response would be ONLY the cleaned up text, so here your response is ONLY:
&quot;Hey, I just wanted to follow up on the meeting from yesterday. I think we should definitely move the deadline to next Friday because the design team still needs more time to finish the mockups. Let me know if that works for you. Thanks.&quot;&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;h2&gt;Using a Local Model&lt;/h2&gt; 
&lt;p&gt;FreeFlow can use OpenAI-compatible local or self-hosted providers instead of Groq. In settings, configure the API base URL and model IDs for your local LLM provider, such as Ollama, LM Studio, or another OpenAI-compatible server. If your transcription backend uses a different endpoint from your LLM backend, set the transcription API URL separately.&lt;/p&gt; 
&lt;p&gt;Local models are often slower than hosted providers, especially on cold start, long recordings, or busy hardware.&lt;/p&gt; 
&lt;details&gt; 
 &lt;summary&gt;Configure longer timeouts for local models&lt;/summary&gt; 
 &lt;p&gt;FreeFlow keeps the default network timeout at 20 seconds, but you can extend it with macOS defaults:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;defaults write com.zachlatta.freeflow transcription_timeout_seconds -float 120
defaults write com.zachlatta.freeflow post_processing_timeout_seconds -float 120
defaults write com.zachlatta.freeflow context_request_timeout_seconds -float 120
&lt;/code&gt;&lt;/pre&gt; 
 &lt;p&gt;The timeout keys are:&lt;/p&gt; 
 &lt;ul&gt; 
  &lt;li&gt;&lt;code&gt;transcription_timeout_seconds&lt;/code&gt;: audio transcription requests&lt;/li&gt; 
  &lt;li&gt;&lt;code&gt;post_processing_timeout_seconds&lt;/code&gt;: transcript cleanup and edit mode requests&lt;/li&gt; 
  &lt;li&gt;&lt;code&gt;context_request_timeout_seconds&lt;/code&gt;: nearby app context requests&lt;/li&gt; 
 &lt;/ul&gt; 
 &lt;p&gt;Only positive values are used. Remove a custom timeout to return to the 20-second default:&lt;/p&gt; 
 &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;defaults delete com.zachlatta.freeflow transcription_timeout_seconds
defaults delete com.zachlatta.freeflow post_processing_timeout_seconds
defaults delete com.zachlatta.freeflow context_request_timeout_seconds
&lt;/code&gt;&lt;/pre&gt; 
&lt;/details&gt; 
&lt;h2&gt;License&lt;/h2&gt; 
&lt;p&gt;Licensed under the MIT license.&lt;/p&gt;</description>
      
      <media:content url="https://opengraph.githubassets.com/4605f3c53ed77c2d64ce723c82c02807ec461f6a816a0a81bcca1172458221a6/zachlatta/freeflow" medium="image" />
      
    </item>
    
  </channel>
</rss>
