- One of Swift’s goals is to become a highly applicable programming language from
task high-level
, UI construction,scripting
, tolow-level system
programming. It’s an ambitious and unfulfilled goal, but there are some features of Swift that make it easy to expand. - One requirement is how the
standard library
works with itsbuilt-in collections
most effectively by reducing the number of instances when theirelement
are copied and moved.
1 / A slice of a binary:
- In Swift, a
slice
is a specialcollection
type that does not actually store anyelement
of its own but act as a proxy (orview
) to allow us to access and work with a subset of a Other separate collections. - For example, we have an array of 10 numbers and we want to get the first 5 numbers to work. This is done using
Range-based
subscripting , as follows:
1 2 3 | <span class="token keyword">let</span> numbers <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">,</span> <span class="token number">4</span> <span class="token punctuation">,</span> <span class="token number">5</span> <span class="token punctuation">,</span> <span class="token number">6</span> <span class="token punctuation">,</span> <span class="token number">7</span> <span class="token punctuation">,</span> <span class="token number">8</span> <span class="token punctuation">,</span> <span class="token number">9</span> <span class="token punctuation">,</span> <span class="token number">10</span> <span class="token punctuation">]</span> <span class="token keyword">let</span> firstFive <span class="token operator">=</span> numbers <span class="token punctuation">[</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token operator"><</span> <span class="token number">5</span> <span class="token punctuation">]</span> |
- At first glance,
firstFive
will have the same type withnumbers
asArray<Int>
. In fact, what we did above is create aslice
ofArraySlice<Int>
- Instead of copying 5 input elements into a new
Array
instance
, instead, thestandard library
only gives us a glimpse into therange
ofelement
help increase performance significantly, especially when working with largecollection
than. - By not performing any duplication or allocating additional memory to the
collection
, aslice
can be instantiated in constant time (O (1). That helps create a fasterslice
+ createslice
as if we were doing it on the originalcollection
.
2 / Prefixes and suffixes:
- Let’s start by looking at how we can use
slicing
to getprefixes
andsuffixes
from thecollection
. For example, we work onTodoApp
:
1 2 3 4 5 6 | <span class="token keyword">struct</span> <span class="token builtin">TodoList</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> name <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token builtin">Item</span> <span class="token punctuation">]</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
- Now, we are building a
feature
that allows ouruser
to quickly see the first three items in a specific list – for example, in theTodayApp
extension oniOS
ormacOS
. We can use the same registration API as we used whenslicing array
our upperslicing array
:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">TodoList</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> topItems <span class="token punctuation">:</span> <span class="token builtin">ArraySlice</span> <span class="token operator"><</span> <span class="token builtin">Item</span> <span class="token operator">></span> <span class="token punctuation">{</span> items <span class="token punctuation">[</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token operator"><</span> <span class="token number">3</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Although the above syntax is very neat, it is a quite dangerous
implementation
. Because we can know how manyTodoList
item
will actually be used, our app maycrash
when accessing the aboveproperty
because just like when retrieving an element from an array,range
registration also causes problems when used with parts from out ofrange
. - While we can test our own limits on
implementation
:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">TodoList</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> topItems <span class="token punctuation">:</span> <span class="token builtin">ArraySlice</span> <span class="token operator"><</span> <span class="token builtin">Item</span> <span class="token operator">></span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> <span class="token keyword">prefix</span> <span class="token punctuation">(</span> <span class="token number">3</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Now our new
API
will work as expected, even ifTodoList
contains fewer than 3item
and ourimplementation
still has O (1) complexity, meaning we can be comfortablecomputed property
it. without the risk of a performance decrease. - However, one thing we must keep in mind when working with
slice
is that they are actually a separate type from the originalcollection
meaning we can pass anArraySlice
to anyAPI
. acceptArray
and vice versa. It gives us full control when aslice
is separated (and itselement
are copied) from its originalcollection
. - For example, we use a different way of the
standard-ibrary
API
prefix
(along with itssuffix
) to divide a package into two separate packages based on theindex
. Since we don’t want ourShipment
model to containArraySlice
, we have to convert our twoslice
into anArray<Package>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <span class="token keyword">struct</span> <span class="token builtin">Shipment</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> destination <span class="token punctuation">:</span> <span class="token builtin">Address</span> <span class="token keyword">var</span> packages <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token builtin">Package</span> <span class="token punctuation">]</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">Shipment</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">split</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token builtin">first</span> <span class="token punctuation">:</span> <span class="token builtin">Shipment</span> <span class="token punctuation">,</span> second <span class="token punctuation">:</span> <span class="token builtin">Shipment</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">guard</span> packages <span class="token punctuation">.</span> <span class="token builtin">count</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token keyword">self</span> <span class="token punctuation">,</span> <span class="token function">Shipment</span> <span class="token punctuation">(</span> destination <span class="token punctuation">:</span> destination <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> splitIndex <span class="token operator">=</span> packages <span class="token punctuation">.</span> <span class="token builtin">count</span> <span class="token operator">/</span> <span class="token number">2</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token function">Shipment</span> <span class="token punctuation">(</span> destination <span class="token punctuation">:</span> destination <span class="token punctuation">,</span> packages <span class="token punctuation">:</span> <span class="token function">Array</span> <span class="token punctuation">(</span> packages <span class="token punctuation">.</span> <span class="token keyword">prefix</span> <span class="token punctuation">(</span> upTo <span class="token punctuation">:</span> splitIndex <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">Shipment</span> <span class="token punctuation">(</span> destination <span class="token punctuation">:</span> destination <span class="token punctuation">,</span> packages <span class="token punctuation">:</span> <span class="token function">Array</span> <span class="token punctuation">(</span> packages <span class="token punctuation">.</span> <span class="token function">suffix</span> <span class="token punctuation">(</span> from <span class="token punctuation">:</span> splitIndex <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- We have calculated the
prefix
andsuffix
of them tadua on the number of particles and the index, but we can also use custom logic. For example, we call theprefix
by:
1 2 | <span class="token keyword">let</span> qualifiedPlayers <span class="token operator">=</span> topPlayers <span class="token punctuation">.</span> <span class="token keyword">prefix</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> score <span class="token operator">></span> <span class="token number">100_000</span> <span class="token punctuation">}</span> |
3 / Dropping elements:
- For example, we want to
remove
any numbers that appear at the beginning of thestring
, to prepare astring
be used as a standard identifier. We can askstring
out all theelement
in theelement
current is anumber
:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">StringProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">trimmingLeadingNumbers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">SubSequence</span> <span class="token punctuation">{</span> <span class="token function">drop</span> <span class="token punctuation">(</span> <span class="token keyword">while</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> isNumber <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- One of the main benefits of
slicing
based APIcollection
in Swift is that they can be initialized without copying. That’s the benefit we have in situations like the one below:
1 2 3 4 5 6 | <span class="token keyword">func</span> <span class="token function">normalizeUsername</span> <span class="token punctuation">(</span> <span class="token number">_</span> username <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">{</span> username <span class="token punctuation">.</span> <span class="token function">trimmingLeadingNumbers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token builtin">filter</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> isLetter <span class="token operator">||</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> isNumber <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Let’s look at how to combine
dopFirst
with theprefix
to easily add paging support to any BidirectionalCollection (including types like Array, Range, etc.). By calling dropFirst first to remove all the elements before the current page starts and then use the prefix to extract a slice of the same size as our page size, we can deploy Pagination extensions like this:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">BidirectionalCollection</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">page</span> <span class="token punctuation">(</span> withIndex pageIndex <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">,</span> size <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">SubSequence</span> <span class="token punctuation">{</span> <span class="token function">dropFirst</span> <span class="token punctuation">(</span> pageIndex <span class="token operator">*</span> size <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token keyword">prefix</span> <span class="token punctuation">(</span> size <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Going back to our TodoList type from earlier, we could then wrap the API above on a slightly higher level of abstraction, giving us a really nice paging method that can be used to display. Show any to-do list in a modal page:
1 2 3 4 5 6 | <span class="token keyword">extension</span> <span class="token builtin">TodoList</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">page</span> <span class="token punctuation">(</span> at index <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">ArraySlice</span> <span class="token operator"><</span> <span class="token builtin">Item</span> <span class="token operator">></span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> <span class="token function">page</span> <span class="token punctuation">(</span> withIndex <span class="token punctuation">:</span> index <span class="token punctuation">,</span> size <span class="token punctuation">:</span> <span class="token number">25</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- At first it may seem strange to return an
ArraySlice
from the aboveAPI
, instead of converting the result into an appropriateArray
. However, we have followed the same rules as thestandard library
that allows the site to decide how and when to convert eachslice
that we can perform additionalstring
withoutstring
performance.