How to assign an optional Binding parameter in SwiftUI?
@Binding var searchTxt: String?
init(searchTxt: Binding<String?>?) {
self._searchTxt = searchTxt ?? Binding.constant(nil)
}
Update: I prefer this one. TextField("", text: $text ?? "default value")
https://stackoverflow.com/a/61002589/4728060
func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
Binding(
get: { lhs.wrappedValue ?? rhs },
set: { lhs.wrappedValue = $0 }
)
}
Optional Binding in parameter SwiftUI
There is special Binding constructor for this purpose
SingleFileView(showSheetModifFile: Binding(self.$showModifFileSheet),
fileToModify: Binding(self.$fileToModify))
Update: alternate solution
struct FileDemoView: View {
@State var showModifFileSheet : Bool? = false
@State var fileToModify : File? = File()
var body: some View {
SingleFileView(showSheetModifFile: $showModifFileSheet, fileToModify: $fileToModify)
}
}
struct SingleFileView: View {
@Binding var showSheetModifFile : Bool?
@Binding var fileToModify : File?
init(showSheetModifFile : Binding<Bool?> = .constant(nil), fileToModify : Binding<File?> = .constant(nil)) {
_showSheetModifFile = showSheetModifFile
_fileToModify = fileToModify
}
var body: some View {
Text("")
}
}
Optional chaining the binding value in SwiftUI textfield
When use the "dot chaining" syntax on a Binding
its a shortcut syntax for creating a Binding
. It doesn't have the same semantics "lookup a property of this thing" that the dot syntax usually holds.
So $food.name
is not going to resolve the binding of food
then reference one of its properties. It going to create a two-way Binding<String>
to the name
property of the food.
Similarly, when you have $food.macroProfile
the value of that expression is a Binding<MacroNutrientProfile?>
... a binding that will directly change a value in food
(and the value it can change is an optional). It is not a resolution of the binding $food
followed by referencing one of that object's properties.
$food.macroProfile?.carb
is nonsensical because $food.macroProfile
is of type Binding<MacroNutrientProfile?>
which is not an optional type. So you see errors.
$food.name
is not nonsensical because it is a Binding<String>
and you're not trying to treat a non-optional value as an optional.
One way to change it is to use a custom binding:
struct Food: Codable, Identifiable {
var id = UUID()
var name: String = ""
var energy: Float?
var water: Float?
var macroProfile: MacronutrientProfile?
}
struct MacronutrientProfile: Codable {
var carb: Float?
var protein: Float?
var fat: Float?
}
struct SomeView : View {
@State var food: Food
let gram = NumberFormatter()
var body : some View {
let carbBinding = Binding<Float?>(get: { food.macroProfile?.carb },
set: { newValue in food.macroProfile?.carb = newValue })
return HStack {
Text("Carbohydrates")
Spacer()
TextField("Grams", value: carbBinding, formatter: gram)
.multilineTextAlignment(.trailing)
.keyboardType(.numberPad)
}
}
}
Optional State or Binding in SwiftUI
Here is working example of optional with State and Binding:
import SwiftUI
struct ContentView: View {
@State private var progress: Int?
var body: some View {
CustomView(progress: $progress)
}
}
struct CustomView: View {
@Binding var progress: Int?
var body: some View {
Button("update") {
if let unwrappedInt = progress { progress = unwrappedInt + 1 }
else { progress = 0 } //<< █ █ Here: initializing! █ █
}
.onChange(of: progress) { newValue in
if let unwrappedInt = progress { print(unwrappedInt) }
}
}
}
How to convert value of optional type Binding T? ? to Binding T? in SwiftUI?
The process of "converting" an optional to a non-optional is unwrapping. The only way you can convert an optional to a non-optional is to provide some default value in the case where the optional is nil
.
You have got a little confused about Swift optional
vs default parameters.
Your problem here is you want your height
argument to be optional (as in the caller doesn't need to specify it), but you shouldn't declare it as an optional
because your object needs there to be an instance of a Binding
- the binding must exist even though its wrapped value may be nil
.
The type wrapped in the binding is an optional Double
and that is what you need to provide as a default value - a binding to a Double?
. You can do this with Binding.constant
struct SomeView {
@Binding var height: Double?
init(height: Binding<Double?> = .constant(nil)) {
self._height = height
}
}
Now your default value is a binding to a Double?
and the wrapped value is nil
If you did want your caller to be able to explicitly pass nil
for the height
binding then you have to deal with the default value in the initialiser itself:
struct SomeView {
@Binding var height: Double?
init(height: Binding<Double?>? = nil) {
self._height = height ?? .constant(nil)
}
}
SwiftUI Optional binding argument on View init
Use .constant binding, like
public init(selMode: String, isPresented:(Binding<Bool>) = .constant(true)) {
UITableView.appearance().separatorStyle = .none
_selMode = State(initialValue: selMode)
_isPresented = isPresented
}
How to optionally pass in a Binding in SwiftUI?
The main problem with what you want to achieve is that when the index is handled by the parent your View needs a @Binding to it, but when it handles the index itself it needs @State. There are two possible solutions.
If the view can ignore the index property when it doesn't have one:
struct ReusableView: View {
@Binding var index: Int?
init(_ index: Binding<Int?>) {
self._index = index
}
init() {
self._index = .constant(nil)
}
var body: some View {
VStack {
index.map { Text("The index is \($0)") }
}
}
}
The advantage is that it is very straightforward - just two initializers, but you cannot change the value of the index when it is handled by ResusableView itself (its a constant).
If the view cannot ignore the index property when it doesn't have one:
struct ReusableView: View {
private var content: AnyView
init(_ index: Binding<Int>? = nil) {
if let index = index {
self.content = AnyView(DependentView(index: index))
} else {
self.content = AnyView(IndependentView())
}
}
var body: some View {
content
}
private struct DependentView: View {
@Binding var index: Int
var body: some View {
Text("The index is \(index)")
}
}
private struct IndependentView: View {
@State private var index: Int = 0
var body: some View {
Text("The index is \(index)")
}
}
}
The clear advantage is that you have a view that can either be bound to a value or manage it as its own State. As you can see ReusableView is just a wrapper around two different views one managing its own @State and one being bound to @State of its parent view.
Related Topics
Pass C Function Callback in Swift
In Swift, Can You Split a String by Another String, Not Just a Character
Contextual Type for Closure Argument List Expects 1 Argument, But 4 Were Specified
Create Nsmanagedobject Subclass... Make a New Error in My Project
iOS Facebook Sdk: Login Doesn't Return Email Despite Permissions Granted
"Unrecognized Selector Sent to Instance" in Swift
How to Write Inline Assembly in Swift
How to Print a String from Plist Without "Optional"
Only First Track Playing of Avmutablecomposition()
Swift Map(_:) Extension for Set()
Make Property of Type and Also Conform to Protocol in Swift
Best Practice for Swift Methods That Can Return or Error
Curl Through Nstask Not Terminating If a Pipe Is Present
Programmatically Creating Constraints Bound to View Controller Margins