UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Day 44 Project 9 Part 2: Problem with preview

Forums > 100 Days of SwiftUI

When I follow the instructions for this project, and add the code below to my project, the preview stops working.

struct Flower: Shape {
    //How much to move this petal away from the center
    var petalOffset: Double = -20
    //How wide to make each petal
    var petalWidth: Double = 100

    func path(in rect: CGRect) -> Path {
        //The path that will hold all of the petals
        var path = Path()

        //Count from 0 through 2*pi moving up by pi/8 each time
        for number in stride(from: 0, to: CGFloat.pi * 2, by: CGFloat.pi / 8) {
            //Rotate the petal by the current value of our loop
            let rotation = CGAffineTransform(rotationAngle: number)

            //Move the petal to be at the center of our view
            let position = rotation.concatenating(CGAffineTransform(translationX: rect.width / 2, y: rect.height / 2))

            //Create a path for this petal, using our properties plus a fixed Y height
            let originalPetal = Path(ellipseIn: CGRect(x: CGFloat(petalOffset), y: 0, width: CGFloat(petalWidth), height: rect.width / 2))

            //Apply the rotation/position transformation to the petal
            let rotatedPetal = originalPetal.applying(position)

            //Add the path for the petal to our flower path
            path.addPath(rotatedPetal)
        }

        //return the path of the completed flower
        return path
    }
}

In the preview/canvas area I get this error message...

Compiling failed: cannot convert value of type 'Int' to expected argument type 'CGFloat'

The previewer stays broken as long as I have this struct defined in my project, even if I never make a call to create an instance of Flower in the body of ContentView. The code will still run just fine if I actually compile it, but the preview can not compile it for some reason.

I have found that I can fix the problem with the previewer by changing this function call

for number in stride(from: 0, to: CGFloat.pi * 2, by: CGFloat.pi / 8) {
        //more code here...
}

to

for number in stride(from: CGFloat.zero, to: CGFloat.pi * 2, by: CGFloat.pi / 8) {
        //more code here...
}

But I guess I'm just wondering if anybody else has run into this problem, or if anybody knows if this is just a bug in ContentView_Previews or if I should actually be explicitly specifying that all of the parameters of stride(from:,to:,by:) are CGFloat every time?

2      

Yes, I also experienced this issue. Thanks for the solution.

Only thing I have to offer as an explanation is that the definition of stride uses Generics and the same type is used for each aprameter. So if two paremeters are CGFloat, the third does as well? Not sure if this worked differently when the material was written.

@inlinable public func stride<T>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> where T : Strideable

2      

Did you replace the ContentView part as shown in the tutorial?

struct ContentView: View {
    @State private var petalOffset = -20.0
    @State private var petalWidth = 100.0

    var body: some View {
        VStack {
            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
                .stroke(Color.red, lineWidth: 1)

            Text("Offset")
            Slider(value: $petalOffset, in: -40...40)
                .padding([.horizontal, .bottom])

            Text("Width")
            Slider(value: $petalWidth, in: 0...100)
                .padding(.horizontal)
        }
    }
}

After this you can modify it with the two small additional changes in the tutorial, and build for & run on a device.

// Second modification
            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
                .fill(Color.red, style: FillStyle(eoFill: true))

// First modification
//            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
//                .fill(Color.red)

// Original
//            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
//                .stroke(Color.red, lineWidth: 1)

Finally you can play around with it, by enabling all three versions putting them in a ZStack. Try them in a different order, etc.

            ZStack {
// Second modification
            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
                .fill(Color.red, style: FillStyle(eoFill: true))

// First modification-ish
            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
                .fill(Color.blue)
                .opacity((petalOffset + 40) / 80)

// Original-ish
            Flower(petalOffset: petalOffset, petalWidth: petalWidth)
                .stroke(Color.green, lineWidth: CGFloat(petalWidth / 10))
            }

2      

Yes, I changed the code in ContentView and got the app working just fine when testing on a device. The only problem I was running into was with the preview.

The preview doesn't seem to be able to compile the code if you don't specify that all of the parameters of the stride(from: to: by:) function are CGFloat, even though the actual compiler can figure it out if you give it two parameters specified as CGFloat and one that is just an unspecified number.

This code will compile on a device or simulator just fine, but won't work in the preview:

for number in stride(from: 0, to: CGFloat.pi * 2, by: CGFloat.pi / 8) {
        //more code here...
}

This code will compile on a device, simulator, or preview:

for number in stride(from: CGFloat.zero, to: CGFloat.pi * 2, by: CGFloat.pi / 8) {
        //more code here...
}

2      

What version of Xcode and what simulators are you using, as I just copy-pasted the code directly, without having to use CGFloat.zero? It could be a bug in Xcode with certain types of simulators.

I had no problems with the preview and live preview for the simulators for iPhone 8, X, SE (2nd Generation), 11, 12 Pro Max.

For reference, I was using the latest released version - Xcode 12.5.1 running iOS 14.5 simulators.

2      

Actually, I just opened the project and tried it again now, and the preview does seem to be working without a problem.

I am using Xcode 12.5.1 now, but I'm not sure if there has been an update since I originally posted this question.

2      

I still experience the problem with Preview and device set to iPod Touch (7th generation) or iPhone 12 and Xcode Version 12.5 (12E262).

@Fly0strich's solution to use CGFloat.zero allows it to work.

I also can run it fine on an actual iPhone 11 or the simulator. But the Preview still does not work.

It leads me to think the Preview uses a quick pass compiler with less capability than the device compiler. Probably done to make preview as fast as possible.

2      

I'm not sure about Xcode 12.5, I can only speak to Xcode 12.5.1?

There could be a bug with Xcode12.5, the simulators and previews.

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.