When to Use Inout Parameters

When to use inout parameters?

inout means that modifying the local variable will also modify the passed-in parameters. Without it, the passed-in parameters will remain the same value. Trying to think of reference type when you are using inout and value type without using it.

For example:

import UIKit

var num1: Int = 1
var char1: Character = "a"

func changeNumber(var num: Int) {
num = 2
print(num) // 2
print(num1) // 1
}
changeNumber(num1)

func changeChar(inout char: Character) {
char = "b"
print(char) // b
print(char1) // b
}
changeChar(&char1)

A good use case will be swap function that it will modify the passed-in parameters.

Swift 3+ Note: Starting in Swift 3, the inout keyword must come after the colon and before the type. For example, Swift 3+ now requires func changeChar(char: inout Character).

Is swift inout parameter a variable or a pointer?

Being a pointer is only side-effect of optimization process for inout parameters. They actually work in different manner using copy-in copy-out behavior. So inside function that parameter is treated just like regular variable, not pointer. If you pass it to another function that takes inout parameter you have to mark it as such.

In-out parameters are passed as follows:

When the function is called, the value of the argument is copied.

In the body of the function, the copy is modified.

When the function returns, the copy’s value is assigned to the original argument.

This
behavior is known as copy-in copy-out or call by value result. For
example, when a computed property or a property with observers is
passed as an in-out parameter, its getter is called as part of the
function call and its setter is called as part of the function return.

As an optimization, when the argument is a value stored at a physical
address in memory, the same memory location is used both inside and
outside the function body. The optimized behavior is known as call by
reference; it satisfies all of the requirements of the copy-in
copy-out model while removing the overhead of copying. Write your code
using the model given by copy-in copy-out, without depending on the
call-by-reference optimization, so that it behaves correctly with or
without the optimization.

In-Out Parameters

Is there any difference between mutating function and inout parameters in Swift?

mutating marks a method. inout marks a parameter. They are completely different things.

Methods marked with mutating can mutate self i.e. set properties of self, reassign self etc.

struct Foo {
var foo: Int

mutating func mutate() {
foo += 1 // this is mutating self
}
}

Parameters marked with inout basically become var variables, as opposed to let constants. You can change them, and the changes will also reflect on the caller's side.

func f(_ x: inout Int) {
x = 10
}

var a = 1
f(&a)
print(a) // 10

inout parameter in Swift

The error should be at the top of the stack trace:

Simultaneous accesses to 0x109fac098, but modification requires exclusive access.

When you pass char1 as a inout parameter to changeChar it is a memory violation to access char1 in any other way until that function returns.

For full details, see SE-176 Enforce Exclusive Access to Memory which added this restriction in Swift 4.

Using inout keyword: is the parameter passed-by-reference or by copy-in copy-out (/call by value result)

The next two paragraphs in the Language Reference describes it more in detail:

In-Out Parameters


This behavior is known as copy-in copy-out or call by value result. For
example, when a computed property or a property with observers is
passed as an in-out parameter, its getter is called as part of the
function call and its setter is called as part of the function return.

As an optimization, when the argument is a value stored at a physical
address in memory, the same memory location is used both inside and
outside the function body. The optimized behavior is known as call by
reference
; it satisfies all of the requirements of the copy-in
copy-out model while removing the overhead of copying. Do not depend
on the behavioral differences between copy-in copy-out and call by
reference.

So it's de facto "pass by reference"

Swift/iOS: How to use inout parameters in functions with AnyObject/Any or Pointers

Better you can create a generic method like below:

func setValue(inout object:T, key: String) {
switch key {
case "String":
object = ("A String" as? T)!
case "UIColor":
object = (UIColor.whiteColor() as? T)!
case "Bool":
object = (true as? T)!
default:
println("Unhandled key: \(key)")
}
}

And calling will be like this:

setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")

Hope it helps!

How can I use inout instead of Binding in SwiftUI?

The reason why you can't use inout here is because inout has a copy-in-copy-out behaviour. The value is passed into the function as a copy, and as soon as the function returns, the modified copy is copied back. You should not think of it as pass-by-reference, thought it can be implemented this way as an optimisation.

Now knowing that, it'd make a lot of sense for the Swift compiler to forbid you from using an inout parameter in an escaping closure, such as using inPutValue in onTapGesture. After all, the modified inPutValue is only copied back when TextView returns, not when someone taps it, so whatever modifications you do to it in onTapGesture is not visible to the caller of TextView at all. See also this answer.

So the value is copied back to the caller as soon as TextView returns. As the error message says, modifying a @State directly when computing body (i.e. "during view update") is not allowed.

Now let's look at the case of Button. Note that this time, the call to inoutFunction(incomingValue: &value) happens inside the button's click handler, rather than in body - meaning value will be written to when the button is pressed. This is allowed.

You can make your TextView to be of a similar form to Button's initialiser by adding a closure argument:

func TextView(update: @escaping () -> Void) -> some View {

return Text("Hello")
.onTapGesture(perform: update)

}

Note that there is nothing inout in this at all, just like there is nothing inout in Button.init.

You can then write your function with an inout parameter:

func inoutFunction(_ b: inout Bool) {
b.toggle()
}

and use it:

@State private var isOn = true

var body: some View {
TextView { inoutFunction(incomingValue: &isOn) }
}

Notice that you don't need inout at all.

TextView { isOn.toggle() }

Is there a good use for inout parameters?

I've used it mostly for adapting to legacy code.= (com interop).

I also tend to use it in code that needs to be performant and indicate success:

bool PerformSomeReadOperation(SomeInput obj, ref int defaultedOutput) { }

where the return value is a notion of success or failure or perhaps an error code and defaultedOutput is a value that comes in with a default value.

Did you know that there is no real difference between out and ref (at least as far as the CLR is concerned)?

When to use delegate, inout or completion in Swift?

I will explain when each method should be used.

A completion block is used when the operation takes time. For example, UIView.animate has a completion block parameter because animating views take time.

A delegate is used only when some of object is present especially when that object can have multiple states. This is widely used for communication between the view and the controller When there is only a method, delegates don't work. For example, a GADInterstitial has a delegate because it can have different states, such as the user dismissing the ad, user clicks the ad and leaves the app, the ad is loaded etc.

Inout parameters are mainly used for passing value types as references. I can't find any usage of this in the iOS SDK because there is no inout in Objective-C. The closest thing to it is UnsafeMutablePointer. Basically, if you want to make a method that takes a bunch of value type arguments and you want to change their value, use inout! Refer to this page for more info.

From my own experience, wrapper objects are rarely used in swift. That is because we have tuples! You can wrap everything in a tuple and pass that around. I don't usually create a new struct or class just to wrap a few parameters. But do use them if your data structure becomes something complicated like [(String, [String: (String, Int)])].



Related Topics



Leave a reply



Submit