Does swift allow code blocks without conditions/loops to reduce local variable scope?
You can use a do
statement to create arbitrary scope in Swift. For example:
func foo() {
let x = 5
do {
let x = 10
print(x)
}
}
foo() // prints "10"
As per The Swift Programming Language:
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.A do statement in Swift is similar to curly braces (
{}
) in C used to
delimit a code block, and does not incur a performance cost at
runtime.Ref: The Swift Programming Language - Language Guide - Statements - Do Statement
What does a do statement without catch block mean?
It's a new scope of code: thus you can use many do statements
if you want to reuse a variable name. Like in the snippet in your question, the variables mars
, sz
and r
exist in both scopes without errors.
A do
statement may be labeled, which gives you the ability to get out of that scope:
scopeLabel: do {
for i in 0..<10 {
for j in 0..<20 {
if i == 2, j == 15 {
break scopeLabel
}
else {
print(i,j)
}
}
}
}
For more details, have a look here.
How to create local scopes in Swift?
Update: In Swift 2.0, you just use the do
keyword:
do {
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}
This was true for Swift pre-2.0:
You can define something similar to this:
func locally(@noescape work: () -> ()) {
work()
}
And then use such a locally
block as follows:
locally {
let g = 42
println(g)
}
(Inspired by locally
in Scala's Predef object.)
UI: do { } in Swift
It's a labeled statement:
A labeled statement is indicated by placing a label on the same line
as the statement’s introducer keyword, followed by a colon.
and it can be used to break away from outsider scopes. An illustrative example is given here.
If the Swift 'guard' statement must exit scope, what is the definition of scope?
It is totally possible to do what you envision, it just happens to not be what that particular code does. return
always exits a method, not the local scope. To do what you wish, you can use a label, and break
:
func testGuardControlFlow () {
let x = 2
let y = 2
func embededFunc () {
breakLabel:
if y == 2 {
guard x == 1 else {
print("oops, number is not 1")
break breakLabel
}
print ("from in embededFunc")
}
print ("I still want this to print even if x != 1")
}
embededFunc()
print("Great, return still allows this to be printed.")
}
testGuardControlFlow()
To add on to vadian's answer:
guard
forces you to exit the scope using a control transfer statement. There are 4 available to you:
return
andthrow
both exit the function/methodcontinue
can be used within loops (while
/for
/repeat-while
)break
can be used in loops (while
/for
/repeat-while
) to exit the immediate scope. Specifying a label to break to will allow you to exit multiple scopes at once (e.g. breaking out of nested loop structure). When using a label,break
can also be used inif
scopes.
Additionally, you may exit the scope by calling a function that returns Never
, such as fatalError
.
with or without [weak self]
The issue is that you’ve made customNetworker
, the CustomNetworker
, a local variable and you lose your strong reference to it as soon as this local variable falls out of scope. When the dataRequest(input:)
method uses a [weak self]
reference, it’s saying that you don’t want dataRequest(input:)
to keep a strong reference to this CustomNetworker
instance, either. As a result, with no strong references, the CustomNetworker
will be deallocated.
You have a few alternatives:
If you remove the
[weak self]
reference in the closure insidedataRequest(input:)
, then it will retain theCustomNetworker
until the closure runs. As long as you don’t save thisfailureHandler
(and other closures) as stored properties, you should be fine. But don’t just throw in a[weak self]
because you read somewhere that you should always use weak references. Use weak references where you need to avoid strong reference cycles, which would not appear to be the case here.The other alternative is to refactor this code, moving this network request routine,
dataRequest(input:)
to some more long-lived object.E.g., we often have a long-lived network manager object that maintains the
URLSession
and has all these network related methods. Then, assuming you’re keeping a strong reference to this network manager instance elsewhere, you don’t need to worry about the object being deallocated when it falls out of scope. This also saves you from having to pass in theURLSession
object for every request. A caller should not be dealing with theseURLSession
instances, anyway.For example, I often use a singleton network layer (kind of equivalent to
URLSession.shared
pattern):final class NetworkManager {
static let shared = NetworkManager()
private var session: URLSession = .shared // or create and configure this session as you need; but one session object is all you need
private init() { }
@discardableResult
func performRequest(...) -> URLSessionTask {
...
let task = session.dataTask(...) { [weak self] data, response, error in
...
}
task.resume()
return task
}
}Then you can do things like:
NetworkManager.shared.performRequest(...) { [weak self] ... in
...
}The other alternative is to just keep a strong reference to this
customNetworker
variable (e.g. make it a property rather than a local variable). That will prevent theCustomNetworker
object from falling out of scope and becomingnil
because there are no more strong references to it.
Somewhat unrelated, but it would appear that you are creating a URLSession
object when you instantiate your CustomNetworker
object, and subsequently never invalidate it. This will leak. You should create a single URLSession
object and use it for all subsequent network requests.
If you do create multiple URLSession
objects, you must invalidate each one when you’re done with it (e.g., finishTasksAndInvalidate
), or else you will leak. But if you just have one session that you keep alive for all future network requests (which is preferred), then that is not necessary.
Using curly braces to segregate a variable that I want to use multiple times in C++
This is a toy case obviously but this is a good practice and 'stand-alone' blocks are there for that purpose.
I happen to believe they're a better way to structure long functions than breaking it down into members which (in many cases) have no separate purpose.
In such a case you can provide a faster, clearer, safer program particularly if there's a comment (possibly one line) introducing each block.
However in this case you might consider:
for ( bool cont(false);!cont;)
Which has the same effect. Variables declared in a for(.;.;.)
statement are confined to the scope of that statement.
In this case you can dodge the whole variable with:
for(;;) //<--- Canonical formulation for 'infinite' loop.
{
getline(cin, teststring);
if (teststring.length() >= 10)
{
cout << "Too long, try again: ";
}
else
{
cout << "Thank you.\n\n";
break; //<--- Escapes the loop.
}
}
Footnote (in response to comments):
You should regard a for
loop as 'syntactic sugar' on a while
loop. That is no different in their performance, etc. and just pick the one that reads best. for(;cond;)
just looks funny.
There may be a tiny (tiny) performance benefit to break
but I happen to think it's actually simpler and more readable in many cases.
If the code were more complex there might be more 'loop end' code so it becomes:
for(bool cont(false);!cont;) {
//Complex code with multiple 'exit' conditions...
if(!cont) {
//Go round again code that won't fit nicely in last term of for loop...
}
}
Whereas using break
just makes a 'swift exit' easier to understand.
They're not (widely) considered to have the 'bad karma' of goto
because they 'go to' a very clearly defined point of execution.
Modifying a semaphore stored in an instance variable from within an Objective-C block
The important semantic distinction here is that when you use the ivar directly in the block, the block takes a strong reference to self
. By creating a local variable that refers to the semaphore instead, only the semaphore is captured (by reference) by the block, instead of self
, reducing the likelihood of a retain cycle.
As for the __block
qualifier, you'd normally use that to indicate that a local variable should be mutable within the referencing block. However, since the semaphore variable is not mutated by the call to signal
, the qualifier isn't strictly necessary here. It still serves a useful purpose from a style perspective, though, in the sense that it emphasizes the lifetime and purpose of the variable.
On the topic of why an ivar can be qualified with __block
,
why would Clang allow this if it shouldn't be done?
Perhaps exactly because capturing an ivar in a block implies strongly capturing self
. With or without a __block
qualifier, if you use an ivar in a block, you're potentially running the risk of a retain cycle, so having the qualifier there doesn't create additional risk. Better to use a local variable (which, by the way, could be a __weak
reference to self
just as easily as a __block
-qualified reference to an ivar) to be explicit and safe.
Is it a bad practice to use an if-statement without curly braces?
The problem with the first version is that if you go back and add a second statement to the if or else clauses without remembering to add the curly braces, your code will break in unexpected and amusing ways.
Maintainability-wise, it's always smarter to use the second form.
EDIT: Ned points this out in the comments, but it's worth linking to here, too, I think. This is not just some ivory-tower hypothetical bullshit: https://www.imperialviolet.org/2014/02/22/applebug.html
Related Topics
"This Class Is Not Key Value Coding-Compliant" Using Coreimage
Remove from Array of Anycancellable When Publisher Finishes
Swift Difference Between Double and Float64
Passing in Variable Number of Args from One Function to Another in Swift
How Is Commoncrypto Used in Swift3
Make Tabview Background Transparent
Swift Cannot Invoke '*' with an Argument List of Type '(Int, Int)'
Scenekit - Why Scnlight Created Automatically in Scnscene
What Was The Reason for Swift Assignment Evaluation to Void
Simulating Pressing The Home Button in Xcode 7 UI Automation
Xcodebuild Commands Failed to Generate Ipa
Apple Watch and iPhone Are Not Connected When The App in Phone Goes to Background
Swiftui CPU High Usage on Real-Time Foreach View Updating (Macos)
Nsmanagedobjectcontext's Propagatesdeletesatendofevent Set to False Causes Error on Save