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 View
s 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
Why Does Type(Of:) Return Metatype, Rather Than T.Type
How to Add Multiple Values for One Key in a Dictionary Using Swift
Removing a Closure from an Array
Weak Method Argument Semantics
iOS Swift Didbegincontact Not Being Called
Using @Fetchrequest(Entity: ) for Swiftui MACos App Crashes
How to Subclass a Class Which Doesn't Have Any Designated Initializers
Make a Type Itself -- Not Its Instances -- Conform to a Protocol
Symbol Is Considered to Be an Identifier, Not an Operator
How to Make Embedded View Controller Part of the Responder Chain
Swiftui: How to Implement Edit Menu in MACos App
How to Use Socket in Swift (Connect, Send and Get Message)
Create a New Window with Nswindow
Draw Mkpointannotation with Title in Mksnapshot Image
Protocol Extension Initializer Forcing to Call Self.Init