How to Create Local Scopes in Swift

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.)

How to make a subscope in Swift?

You can try

do {   
// insert sub scope code
}

In Swift, what is the scope of local variable if it is used inside a closure?

This is why they're called closures.

Closures can capture and store references to any constants and
variables from the context in which they’re defined. This is known as
closing over those constants and variables. Swift handles all of the
memory management of capturing for you.

https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID103

How can I expand the scope of a variable in Swift

As mentioned, you have two num1 variables. The 2nd one is scoped to just the block of the 2nd if statement.

You also have an issue that readLine returns an optional String, not an Int.

You probably want code more like this:

var num1: Int?

if userChoice == "add" {
print("Enter first number")
if let line = readLine() {
num1 = Int(line)
}
}

print ("\(num1)")

Of course you may now need to deal with num1 being nil.

One option is to properly unwrap the value:

if let num = num1 {
print("\(num)")
} else {
print("num1 was nil")
}

Swift/iOS - How to use a value from one scope/function and pass it into another?

With Xcode 13 Beta and Swift 5.5

This is a problem that we can now solve with Async/Await's Continuations

We would first make a function that converts the callback into an awaitable result like:

func getXRotation(from motion: CMMotionManager) async throws -> Float {
try await withCheckedThrowingContinuation { continuation in
class GyroUpdateFailure: Error {} // make error to throw
motion.startGyroUpdates(to: .main) { (data, error) in
if let myData = data {
continuation.resume(returning: Float(myData.rotationRate.x))
} else {
throw GyroUpdateFailure()
}
}
}
}

Then we can assign the variable and use it like so:

let gyroX = try await getXRotation(from: motion)
callSomeOtherFunction(with: gyroX)

With Xcode <= 12 and Combine

In the current release of Swift and Xcode we can use the Combine framework to make callback handling a little easier for us. First we'll convert the closure from the motion manager into a "Future". Then we can use that future in a combine chain.


func getXRotation(from motion: CMMotionManager) -> Future<CMGyroData, Error> {
Future { promise in
class GyroUpdateFailure: Error {} // make error to throw
motion.startGyroUpdates(to: .main) { (data, error) in
if let myData = data {
promise(.success(myData))
} else {
promise(.failure(GyroUpdateFailure()))
}
}
}
}

// This is the other function you want to call
func someOtherFunction(_ x: Float) {}

// Then we can use it like so
_ = getXRotation(from: motion)
.eraseToAnyPublisher()
.map { Float($0.rotationRate.x) }
.map(someOtherFunction)
.sink { completion in
switch completion {
case .failure(let error):
print(error.localizedDescription)
default: break
}
} receiveValue: {
print($0)
}


There are some important parts to the combine flow. The _ = is one of them. The result of "sinking" on a publisher is a "cancellable" object. If we don't store that in a local variable the system can clean up the task before it fishes executing. So you will want to do that for sure.

I highly recommend you checkout SwiftBySundell.com to learn more about Combine or Async/Await and RayWenderlich.com for mobile development in general.

Access variable in outer scope

In your code, let cell = ... in the if-block introduces a new variable
cell which "hides" or "shadows" the cell variable from the outer
scope. There is – as far as I know – no language feature to access
the outer variable with the same name.

You can achieve a similar effect with an immediately evaluated closure,
which creates and configures the cell in a local scope, and passes the
result back to the outer scope:

    let cell: UITableViewCell
if indexPath.section == 0 {
cell = {
let cell = tableView.dequeueReusableCellWithIdentifier("awesomeCell", forIndexPath: indexPath) as! AwesomeTableViewCell
cell.delegate = self
return cell
}()
} else {
// ...
}

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

How do I get the variable out of the local scope and be able to use that variable in another view or other functions in Swift, Xcode?

The reason why you can't access the model constant is that your model was declared in a function with lower hierarchy than where the print function is located.

The way Swift variables work is that they can only be accessed on any sub-class/function/method with a lower hierarchy than itself (i.e. variables declared inside a function cannot be used outside the function itself).

To be able to access your model variable anywhere in every swift file in your project, you should use a global variable, which is defined by the official Swift programming guide as:

Variables that are defined outside of any function, method, closure, or type context. Global constants and variables are always computed lazily.

Which means to say that to make model a global variable, you should declare it outside of your LoginModel class, or any other similar classes, functions, methods, closures, or type contexts.

If you do not need to access model everywhere but just need to print it, you can either move your print function into the networkModel.response function, or declare your model constant outside of the networkModel.response function.



Related Topics



Leave a reply



Submit