Xcode Beta 6 Type of expression is ambiguous without more context navigationlink
I'll quote from the macOS Catalina 10.15 Beta 6 Release Notes:
The Binding structure’s conditional conformance to the Collection
protocol is removed. (51624798)If you have code such as the following:
struct LandmarkList: View {
@Binding var landmark: [Landmark]
var body: some View {
List(landmarks) { landmark in
Toggle(landmark.value.name, isOn: landmark[\.isFavorite])
}
}
}
Define the following collection type:
struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
typealias Index = Base.Index
typealias Element = (index: Index, element: Base.Element)
let base: Base
var startIndex: Index { base.startIndex }
var endIndex: Index { base.endIndex }
func index(after i: Index) -> Index {
base.index(after: i)
}
func index(before i: Index) -> Index {
base.index(before: i)
}
func index(_ i: Index, offsetBy distance: Int) -> Index {
base.index(i, offsetBy: distance)
}
subscript(position: Index) -> Element {
(index: position, element: base[position])
}
}
extension RandomAccessCollection {
func indexed() -> IndexedCollection<Self> {
IndexedCollection(base: self)
}
}
Then, update your code to:
struct LandmarkList: View {
@Binding var landmarks: [Landmark]
var body: some View { // Does often give error on id: \.1.id
List(landmarks.indexed(), id: \.1.id) { (index, landmark) in
Toggle(landmark.name, isOn: self.$landmarks[index].isFavorite)
}
}
}
Your code also takes a Binding<[JobDetails]>
with $jobList.jobDetails
, but Binding<[JobDetails]>
does not conform to the Collection protocol anymore.
Note to the solution above however, that I got cases where \.1.id
was not recognized because the compiler didn't understand \.1
is referring to the second element in the tuple IndexedCollection
defines, but it's possible that I used it wrong. It's possible to rewrite it however which makes it work.
Example using IndexedCollection
struct AnotherIndexedView_NeedsEnv: View {
@EnvironmentObject var modalManager: ModalManager
var body: some View {
ZStack {
SwiftUI.ForEach(modalManager.modals.indexed()) { m in
ModalView(currentModal: self.$modalManager.modals[m.index]).environmentObject(self.modalManager)
}
}.onAppear(perform: {self.modalManager.fetchContent()})
}
}
SwiftUI Xcode 11 beta 5 / 6: Type of expression is ambiguous without more context
After your update in your answer, I see some changes needed:
- Use
ObservableObject
(no need to useCombine.ObservableObject
) - Missing function
scanPassport
, I added a bogus one. willChange
no longer exists, it is nowobjectWillChange
. And it is autosynthesize for you.
import SwiftUI
class ClPassport : ObservableObject , Identifiable {
@Published var mrz : String = "" //{ didSet { update() } }
var isValid : Bool {
return true
}
func update() {
objectWillChange.send()
}
func getMRZKey() -> String {
return ""
}
}
struct ContentView : View {
@ObservedObject var passportDetails = ClPassport()
var body: some View {
ZStack{
VStack(alignment: .leading){
HStack{
Spacer()
Button(action: {
self.scanPassport( mrzKey: self.passportDetails.getMRZKey() )
}) {
Text("Read Chip")
.font(.largeTitle)
.foregroundColor(passportDetails.isValid ? .primary : Color.secondary.opacity(0.25))
.padding()
}.padding()
.background(Color.white.opacity(passportDetails.isValid ? 1 : 0.5))
.cornerRadius(15)
.padding()
.disabled( !passportDetails.isValid )
Spacer()
}
TextField("MRZ", text: $passportDetails.mrz)
}
}
}
func scanPassport( mrzKey: String ) {
//do stuff with mrzKey
}
}
NavigationLink with SwiftUI: Type of expression is ambiguous without more context
You used NavigationLink
instead of NavigationView
in the very first line of var body
inside struct signUp
.
So this:
var body: some View {
NavigationLink{
,,,
}//nav
}
should be:
var body: some View {
NavigationView{
,,,
}//nav
}
NavigationLink
is like a trigger to navigate, while NavigationView
is responsible to handle visuals, animations and other stuff about navigating.
And note that since SwiftUI is very young, Xcode is not able to detect what is the issue exactly and sometimes shows wrong or unclear messages. But apple is constantly working on it and improving it release by release.
SwiftUI: Type of expression is ambiguous without more context, When passing ObservableObject between Views
It seems that you are using ObservableObject
like a BindableObject
. The BindableObject
is replaced from beta 4 (?).
BindableObject is replaced by the ObservableObject protocol from the
Combine framework.
The didChange
changed in favour of objectWillChange
and he should be called inside the willChange
observer.
To avoid repeating yourself the @Published
attribute synthesizes the willChange
for you.
You can manually conform to ObservableObject by defining an objectWillChange publisher that emits before the object changes. However, by default, ObservableObject automatically synthesizes objectWillChange and emits before any @Published properties change.
class User: ObservableObject {
@Published var name: String = ""
@Published var email: String = ""
}
And use the @ObservedObject
if you want a binding of your ObservableObject
:
struct MyView: View {
@ObservedObject var user: User = User()
var body: some View {
TextField("Name", text: $user.name)
}
}
If you continue to have problem because you are using @EnvironmentObject
try to look at: Change to @Published var in @EnvironmentObject not reflected immediately
Type of expression is ambiguous without more context on function that returns some View
SwiftUI just mis-detected place of error - the URL is incorrectly created.
Here is fixed part. Tested with Xcode 12.1 / iOS 14.1
Link(destination: URL(string: buttons[button].url)!, label: {
Image(buttons[button].icon)
})
Type of expression is ambiguous without more context in `ForEach` over array of custom class
It seems like you didn't conform to ExpensePeriod
in ExpenseYear
you are missing start
and end
variables (most likely it's the source of error, but it's hard to tell)
After conforming, if the error persists I would replace in the loop the MonthlyListView
view with Text
and I would keep replacing stuff until I find the source of the error.
This error usually occurs when you are missing a keyword or formatting a loop. Most of the time it just means the compiler can't interpret what you wrote.
I would solve the issue but the code above is missing stuff to be able to run it just by copying and pasting it.
EDIT:
So your issue lies in the forEach
because if you pay close attention, your code look like this ForEach(ExpenseYear.array(from: expenses.last!, to: expenses.first!))
however, expenses is defined as follows var expenses: FetchedResults<Expense>
where each item from this array will be of type Expense
in your ExpenseYear
array your header looks like this tatic func array(from startDate: Date, to endDate: Date) -> [ExpenseYear]
which the first and 2nd parameter are of type Date
yet you are passing them an item of type Expense
. expenses.last!
returns a Expense
object and that's not a Date
! so to solve the issue you would first have to do something like this expenses.last!.datetime!
So changing your code to this
ForEach(ExpenseYear.array(from: expenses.last!.datetime!, to: expenses.first!.datetime!), id: \.id) { expense in
should solve your problem. Keep in mind the following
Change this code to reflect everywhere in your app, I only changed it in 1 single instance as I have commented out the rest of your code.
Force unwrapping is always a bad idea, so I would suggest you handle dates correctly but guard unwrapping them first.
Also, I know you commented that I didn't need to implement start
and end
in ExpenseYear
but unfortunately, I wasn't able to compile without implementing them so I had to.
Alternatively, you can change the .array
protocol to take in an Expense
instead of Date
and then you handle how to return an array from the object Expense
so your protocol would look something like this
static func array(from startExpense: Expense, to endExpense: Expense) -> [Period]
and implementation can be something like this
static func array(from startExpense: Expense, to endExpense: Expense) -> [ExpenseYear] {
guard let startDate = startExpense.datetime, let endDate = endExpense.datetime else {
return []
}
return array(of: .year, from: startDate, to: endDate)
}
where you have already taken care of guarding against nil dates and you don't have to change anything except implementation (I honestly would prefer this method)
I know to implement the second method you would have to change how you set your protocol and bunch of other stuff, so what you can do is instead pass an optional Date
to your array
, something like this static func array(from startExpense: Date?, to endExpense: Date?) -> [Period]
and then guard unwrap them else return empty array. But you still have the issue of unwrapping .last
and .first
expense in your ForEach
loop.
Good luck with the rest!
Related Topics
How to Disable Vertical Scroll in Tabview with Swiftui
Value of Optional Type Cgfloat Not Unwrapped Error in Swift
Why Should Not Directly Extend Uiview or Uiviewcontroller
Is This a Good Way to Display Asynchronous Data
Call Completion Block When Two Other Completion Blocks Have Been Called
Convert Generic Free Function into Array Extension
Obj-C Cocoapods + Swift Framework
Getting Dyld_Fatal_Error After Updating to Xcode 6 Beta 4 Using Swift
Avaudioengine Crashes When Plug Headphones in or Out
Suddenly Getting Compiler Crash "Arrayforcecast" in Swift Xcode Beta 6
Why in Swift We Cannot Adopt a Protocol Without Inheritance a Class from Nsobject
Make Property of Type and Also Conform to Protocol in Swift
How to Test Whether Generic Variable Is of Type Anyobject
How Replace Position++ Code to Make It Swift 3 Compatible
Make Int Round Off to Nearest Value
iOS 10 Imessage App Extension: How to Calculate the Height of the Extra Tall Navbar