Type '()' Cannot Conform to 'View'

Type '()' cannot conform to 'View'

There is a great deal to unpack in this question, but we will start with the simple first. Views are for displaying something on screen. Nothing more. The reason you are having issues with the print() statements is that they are for printing to the console, not the screen. Therefore, the compiler gives you an error. To fix this, use Text like @JoakimDanielson said:

struct SummaryView: View {
var workoutManager: WorkoutManager //This var must be declared

var avgValue = 1.5
var roundedKarvonenValue: Double
var itemX = ["A", "B", "C", "D", "E", "F", "G", "H"]
var itemY = ["I", "J", "K", "L", "M", "N", "O", "P"]

var body: some View {
ScrollView {
VStack(alignment: .leading) {
if workoutManager.averageHeartRate < roundedKarvonenValue{
Text(itemX[0])
} else {
Text(itemY[0])
}
}
}
}
}

As to your second part as to where to place your functions, is not as clear cut. You should look up MVVM architecture to gain an understanding of the standard way to structure your app in SwiftUI. Right now, you are simply displaying data from HealthKit using Apple's WWDC class WorkoutManager(I presume).

At the very basic level, if your function has to do with changing how the data is displayed, it stays in the View. If the function fundamentally changes something about your Model or is needed by multiple views, it should go into the Model. That is a judgment call.

So, for your code, you are showing a random element from a variable declared in a view. That is all local stuff, so the function stays in the view. Adding the func randomElement() and cleaning your code up a bit more leaves you with this:

struct SummaryView: View {
// If you are not changing the variables, declare them as constants. This uses less memory.
let workoutManager: WorkoutManager
let avgValue = 1.5
let roundedKarvonenValue: Double
let itemX = ["A", "B", "C", "D", "E", "F", "G", "H"]
let itemY = ["I", "J", "K", "L", "M", "N", "O", "P"]

var body: some View {
ScrollView {
VStack(alignment: .leading) {
// I turned your if statement into a Terniary Conditional Operator to shrink the amount of code.
Text(workoutManager.averageHeartRate < roundedKarvonenValue ? randomElement(itemX) : randomElement(itemY))
}
}
}

func randomElement(_ stringArray: [String]) -> String {
let end = stringArray.count - 1
let index = Int.random(in: 0...end)
return stringArray[index]
}
}

Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols; calling functions with SwiftUI

You are doing this:

if play
{
MyWatchView.self.playSound()
}

in a context where only Views are expected. The return type of the function is Void (or ()), which is why you are getting the error.


If you want to just play a sound when you click the Toggle, you probably want to use a Button instead:

Button(action: {
MyWatchView.self.playSound()
}) {
Text("")
}

If you want a Toggle (e.g., to update a Bool variable), you can do this:

Toggle(isOn: $play)
{
Text("")
}
.padding(.trailing, 30.0)
.hueRotation(Angle.degrees(45))
.onTapGesture {
MyWatchView.self.playSound()
}

Type 'any View' cannot conform to 'View' on protocol with generics

If I understand correctly, you want a specialised version of the View protocol, where Body is CalculationComponent<some View>, and you don't want to write explicitly what "some View" is when conforming to the protocol, plus some other requirements.

You can add an associated type to CalculationView,

protocol CalculationView: View {
associatedtype Content: View

var mainCalculation: String { get set }
var secondaryCalculation: String { get set}
var body: CalculationComponent<Content> { get } // Type 'any View' cannot conform to 'View'
}

and then say CalculationComponent<some View> when conforming to the protocol:

struct CropFactorCalculatorView: CalculationView {

@State internal var mainCalculation: String = ""
@State internal var secondaryCalculation: String = ""

var body: CalculationComponent<some View> {
CalculationComponent(
mainCalculation: $mainCalculation,
secondaryCalculation: $secondaryCalculation
) {
VStack {
Text("Some Text")
Text("Some Other Text")
}
}
}

}

Type '()' cannot conform to View (except it definitely is a View, no shenanigans this time)

Shenaniganically, you are trying to use ViewBuilder syntax in the trailing closure, but you didn't adorn content with the @ViewBuilder annotation. So Swift infers that the trailing closure returns () (also called Void).

Change the init declaration to mention @ViewBuilder:

struct CompatibilityPicker<blah blah blah>: View where blah blah blah {

init(
_ label : Label,
selection : SelectionValue,
@ViewBuilder content : @escaping () -> Content
// ^^^^^^^^^^^^
) {
blah blah blah

UPDATE

    @Binding private var _selection : SelectionValue

blah blah blah

init(_ label : Label, selection : SelectionValue, content : @escaping () -> Content) {
self.label = label
self._selection = selection
self.content = content
}

The _selection variable is wrapped by the Binding wrapper, which means that it is really a computed property. The stored property is named __selection (note the two underscores) and has type Binding<SelectionValue>. Because _selection is a computed property, init cannot mention it until all stored properties are initialized. Probably you should change init to take a Binding<SelectionValue> argument instead of a SelectionValue argument:

    init(
_ label : Label,
selection : Binding<SelectionValue>,
@ViewBuilder content : @escaping () -> Content
// ^^^^^^^^^^^^
) {
self.label = label
self.content = content
__selection = selection
}

UPDATE 2

I looked at your other question and your code here and I think I know what you mean by “it doesn't work with anything but Int”.

The problem as that, when you say Text("Easy").tag(0), Swift treats 0 as an Int. If your Picker's SelectionValue is, say, Int16, then indeed the Picker will not be able to use the 0 tag because the types don't match.

You can make your tag work with Picker by giving 0 the correct type. For example: Text("Easy").tag(0 as Int16).

However, my recommendation is that you stop mucking about with CompatibilityPicker. It is a symptom of primitive obsession. The idiomatic solution is to use an enum for your tags:

enum Difficulty: Hashable {
case easy
case medium
case hard
}

struct Demo1: View {
@State var difficulty: Difficulty = .easy

var body: some View {
Picker("Difficulty", selection: $difficulty) {
Text("Easy").tag(Difficulty.easy)
Text("Medium").tag(Difficulty.medium)
Text("Hard").tag(Difficulty.hard)
}
}
}

You could go even further and do this:

extension Difficulty: CaseIterable { }

extension Difficulty {
var stringKey: LocalizedStringKey {
switch self {
case .easy: return "Easy"
case .medium: return "Medium"
case .hard: return "Hard"
}
}
}

struct Demo2: View {
@State var difficulty: Difficulty = .easy

var body: some View {
Picker("Difficulty", selection: $difficulty) {
ForEach(Difficulty.allCases, id: \.self) {
Text($0.stringKey).tag($0)
}
}
}
}

how do i fix Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols

This is because in the body of the View you need to return a view. You can't just perform calculations etc. like in a normal function.

You can remove this code (which doesn't return a View and thus the compilation is failing):

else if gameState == 1 {
if self.rand() == self.collor {
self.text = "you won"
self.data = 1
}
}

and place it in you button's action:

if gameState == 0 {
...
TextField("a number", text: $sats)
Button(action: {
self.intsats = Int(self.sats) ?? 0
if self.intsats == 0 || self.intsats > self.data {
self.etext = "not valid number or you do not have enuf mony"
} else {
self.gameState = 1
if self.rand() == self.collor { // <- move it here
self.text = "you won"
self.data = 1
}
}
}) {
Text("bet")
}
}


Related Topics



Leave a reply



Submit