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
Does Swift Have Short-Circuiting Higher-Order Functions Like Any or All
Swiftui [Bug] Navigationview and List Not Showing on iPad Simulator Only
For-In Loops Multiple Conditions
Opening Import File for Module 'Swift': Not a Directory
Swiftui - How to Change Text Alignment of Label in Toggle
Swift: Cast Any Object to Int64 = Nil
How to Animate Opacity Using Swift
How to Display an Int Without Commas
How to Avoid Duplicate Key Error in Swift When Iterating Over a Dictionary
Cast Any to Float Always Fails in Swift4.1
Create Endless Cgpath Without Framedrops
Convert String to Nsdate in Swift
Display Table View When Searchbar (From Searchcontroller) Begin Edited Swift
What's Wrong with My #If Target_Os_Simulator Code for Realm Path Definition
Why Upload Alamofire Background Request Don't Executes in Background