Other than labels being used to break loops (change control flow), in your particular example it's probably being used to organize the code.
So, in:
UI: do {
//...
}
UI:
is a Labelled Statement where UI
is a user defined label name that should be descriptive enough to indicate or hint to the reader of it's purpose
Labeled Statement
You can prefix a loop statement, an if statement, a switch statement,
or a do statement with a statement label, which consists of the name
of the label followed immediately by a colon (:). Use statement labels
with break and continue statements to be explicit about how you want
to change control flow in a loop statement or a switch statement
Ref: https://docs.swift.org/swift-book/ReferenceManual/Statements.html#ID439
do { }
is a Do Statement
Do Statement
The do statement is used to introduce a new scope and can optionally
contain one or more catch clauses, which contain patterns that match
against defined error conditions. Variables and constants declared in
the scope of a do statement can be accessed only within that scope.
Ref: https://docs.swift.org/swift-book/ReferenceManual/Statements.html#ID533
//...
is all the code within the scope of do
Usage Example:
In a monolithic function, in order to improve code readability and segregate the internal logics, a labeled do statement can be used.
So, if this is a monolithic function:
func update() {
var hasUpdatedDatasource = false
print("setting datasource")
//N lines of code related to datasource
let strings = ["update", "Datasource"]
print(strings.joined())
hasUpdatedDatasource = strings.count > 2
print("setting something")
//N lines of code related to something
if hasUpdatedDatasource {
print("setting some more stuff")
//N lines of code related to something more
}
print("setting UI")
//N lines of code related to UI
}
Here we see multiple lines of code in which you may be creating/modifying variables. Basically alot of soup code that would make it hard to figure out which set of code lines is handling which feature or part of the function.
Using a labeled do statement, as in your case, will make the code a bit more readable like so:
func update() {
var hasUpdatedDatasource = false
updateDatasource: do {
//do datasource related modification
//N lines of code go here
let datasource = ["update", "Datasource"]
print(datasource.joined())
hasUpdatedDatasource = strings.count > 2
}
doSomething: do {
print("doSomething")
//N lines of code go here
guard hasUpdatedDatasource else { break doSomething }
print("doSomething: More")
//N lines of code go here
}
updateUI: do {
print("updateUI")
//N lines of code go here
}
}
This allows you to make a set of code lines into block of codes with a descriptive label name and shows the logic flow more clearly.
You can access and modify variables from above it's do
scope, and since it has it's own scope, variables created inside are only accessible here.
This can prevent variables from lingering unnecessarily till the end of the function.
NOTES:
updateDatasource
created a local variable datasource
which won't be available outside it's scope, AND... modified a variable hasUpdatedDatasource
which is local to the entire function
doSomething
has a break statement that can break itself anytime by referring to it's label name
It does make the code more readable but not necessarily more maintainable as it's statefull.
Personally, I prefer splitting large functions into smaller or nested functions. But this does not mean that labeled do statements don't have their place.
If it makes your code better, go for it.