Using ChatGPT to Learn SwiftUI – Does It Work?

Since its launch in November 2022, OpenAI’s text generator ChatGPT has drawn a lot of attention with its highly competent, conversational answers to a wide array of questions on various topics. Built on top of OpenAI’s GPT-3 family of large language models, it can understand natural language and generate written content based on user prompts.

ChatGPT’s capabilities have themselves prompted an exploration of potential use cases in different domains – from school tasks to content marketing. As an iOS engineer, I got the idea to try out ChatGPT in combination with another reasonably new technology, SwiftUI. 

In this article, we’ll evaluate the accuracy of ChatGPT’s answers and assess whether the tool can help enhance the SwiftUI learning experience. Let’s catch a glimpse into the future of learning, coding, and building new things.

Using ChatGPT to understand code in SwiftUI

Starting with the basics, let’s check what ChatGPT can do for somebody new to SwiftUI. Like any confused developer coming to a new technology, I prompted it with a very natural and simple sentence:

I am building an app in SwiftUI and don’t know where to start.

The chatbot’s response was:

It’s great that you’re building an app in SwiftUI! Here are some steps you can take to get started:

1

Familiarize yourself with the basics of SwiftUI. You can do this by reading through Apple’s documentation, or by working through a tutorial.

2

Think about what your app will do and what it will look like. You can start by sketching out your app’s user interface and defining its functionality.

3

Set up a new Xcode project and begin building your app. You can use the “Single View App” template as a starting point and build from there.

4

As you build your app, you can use the SwiftUI preview feature to see how your code changes will look in real-time.

I hope this helps you get started with your SwiftUI app! Let me know if you have any other questions.

This is a pretty good start, both for my conversation with ChatGPT and for anyone actually onboarding to SwiftUI. This response is 10/10, I couldn’t have written it better myself.

Let’s move on to another common situation a non-experienced developer may encounter early on. When learning a new technology, you’ll often stumble upon a piece of code that you don’t understand or need some guidance with. 

I asked the chatbot a simple question:

What does this code do?

	struct Movie: Identifiable {
    let id: UUID
    let title: String
    let releaseYear: Int
    let posterImage: Image
}

struct MovieList: View {
  let movies: [Movie]

  var body: some View {
      List {
        ForEach(movies, id: \.id) { movie in
          HStack {
            movie.posterImage
              .resizable()
              .frame(width: 50, height: 50)
            Text(movie.title)
            Spacer()
            Text("\(movie.releaseYear)")
          }
        }
      }
    }
}

This was the answer:

This code defines two `struct`s in SwiftUI: `Movie` and `MovieList`

The `Movie` struct represents a movie with an `id` of type `UUID`, a `title` of type `String`, a `releaseYear` of type `Int`, and a `posterImage` of type `Image`

The `MovieList` struct represents a view that displays a list of movies. It has a single property `movies` of type `[Movie]`, which is an array of `Movie` structs. The `MovieList` struct conforms to the `View` protocol, which means it can be used to build a user interface in SwiftUI. The `body` property of the `MovieList` struct is a computed property of type `some View`. It returns a `List` view that displays a list of movies. The `List` view is populated using a `ForEach` loop, which iterates over the `movies` array and creates a row for each movie. Each row consists of an `HStack` view that contains the movies’s poster image, title, and release year. The poster image is made resizable and given a fixed size using the `resizable()` and `frame(width:height)` modifiers. The title and release year are displayed as text using the `Text` view. The `Spacer` view is used to push the release year to the right side of the row.

This is a pretty detailed explanation that demonstrates knowledge of key SwiftUI concepts and components, like HStack and Spacer, but also the View protocol. The result can be rated as completely accurate. Another 10/10.

However, wanting to get into more detail, I asked it:

Why does the Movie model need to conform to Identifiable protocol?

Here is how ChatGPT replied:

The `ForEach` view in SwiftUI requires that the items in its collection conform to the `Identifiable` protocol. The `Identifiable` protocol has a single requirement: that the conforming type has an `id` property of type `Hashable`

In this case, the `Movie` struct conforms to the `Identifiable` protocol by having an `id` property of type `UUID`. This allows the `ForEach` loop to create a unique identifier for each movie in the list and use it to identify each movie as it is rendered in the list. 

The `ForEach`view uses the `id` property of each movie to create a unique identifier that it can use to track the movie as it is rendered in the list. This is necessary because the `ForEach`view reuses rows in the list as the user scrolls. By using the `id` property to identify each movie, the `Foreach`view can ensure that the correct movie is displayed in each row as it is reused.

The answer looks pretty straightforward. However, it’s not completely correct. ForEach doesn’t have any mechanisms for reusing cells and does no such thing. On the other hand, List does, so maybe this caused ChatGPT’s confusion and resulted in a somewhat incorrect answer. ForEach is a simple component that loads all the views at once but requires identifiable models because of UI updates, not because rows are reused as the user scrolls. 

I would advise caution here because while answers may look plausible, they will not necessarily always be correct. So it’s best always to double-check and ask many follow-up questions to get the right answer.

Using ChatGPT to improve code in SwiftUI

Now that we have the basics down, let’s take it a step further and see if ChatGPT can help me improve my code and explain what I did wrong.

I asked another simple question and provided a chunk of code.

Can you improve this code?

	List {
    ForEach(movies) { movie in
        HStack {
            movie.posterImage
                .resizable()
                .frame(width: 50, height: 50)
            Text(movie.title)
            Spacer()
            Text("\(movie.releaseYear)")
        }
}
struct MovieList: View {
    var body: some View {
        List {
            ForEach(movies) { movie in
                HStack {
                    movie.posterImage
                        .resizable()
                        .frame(width: 50, height: 50)
                    Text(movie.title)
                    Spacer()
                    Text("\(movie.releaseYear)")
                }
          }
        }
    }
}

This is what ChatGPT had to say in response:

Here are a few suggestions for improving the code:

1

You can make the code easier to read by adding some vertical whitespace between the `List` view and the `ForEach` loop. This will help to visually separate the list from the rest of the view. 

2

You can make the code more efficient by using the `id` parameter of the `ForEach` loop to specify a unique identifier for each movie. This will allow the `ForEach` loop to track each movie efficiently as it is rendered in the list. 

3

You can make the code more flexible by using a `MovieRow` view to display each movie in the list. This will allow you to reuse the movie row code n other views, and will make it easier to modify the appearance of the movie rows.

This was the refactored code provided by ChatGPT:

	struct MovieRow: View {
    let movie: Movie

    var body: some View {
        HStack {
            movie.posterImage
                .resizable()
                .frame(width: 50, height: 50)
            Text(movie.title)
            Spacer()
            Text("\(movie.releaseYear)")
        }
    }
}

struct MovieList: View {
    let movies: [Movie]

    var body: some View {
        List {
            ForEach(movies, id: \.id) { movie in
                MovieRow(movie: movie)
            }
        }
    }
}

Let’s analyze the proposed solution. The first bullet is mostly useless as there is no point in adding an extra line between the List and ForEach components. I would advise against this suggestion. The ChatGPT’s proposition is probably based on general programming language style guides that are not really relevant in SwiftUI.

The second bullet doesn’t have any performance gain as opposed to just conforming the model to Identifiable. The last bullet is the best one; it suggests a pretty good separation of view, just like Apple advises. 

Some bullets were not really useful or wholly related to this technology, but I can understand why they came up. ChatGPT focused on some general rules for making your code more readable and cleaner. The last bullet was absolutely in line with SwiftUI and provided an excellent explanation. 

Moving on to a different issue, it’s important to keep in mind how SwiftUI significantly changes how we write and think about UI. The constraints of UIKit, as well as its tedious setup, are gone. Many newbies have a hard time adapting to this and need some help in the process. Let’s see how ChatGPT understands SwiftUI in its core, its APIs, and whether it can help me transition faster.

I wondered how ChatGPT handles width and height tasks, something very tricky in the SwiftUI framework, which is declarative by nature.

My prompt was:

How to make Image resize to a width of the screen subtracted by 20 points and have the same height?

This is what ChatGPT suggested:

To make the image resize to a width of the screen subtracted by 20 points and have the same height, you can use the `GeometryReader` view to get the width of the screen and the `aspectRatio` modifier to preserve the aspect ratio of the image.

In this example, the `GeometryReader` view reads the width of the screen and passes it to the `frame(width:)` modifier as the `geometry.size.width` value. The `aspectRatio(contentMode:)` modifier is used to preserve the aspect ratio of a view. The contentMode parameter determines how the view’s aspect ratio should be calculated. For example, a `Text (“Hello, world!”)` with an aspectRatio of 2:1 and contentMode `.fit` have the width twice the height and the text will be scaled to fit the parent view.

Here’s an example of how you could modify the `MovieRow` struct to achieve this:

	struct MovieRow: View {
    var movie: Movie

    var body: some View {
        GeometryReader { geometry in
            HStack {
                self.movie.posterImage
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: geometry.size.width - 20)
                Text(self.movie.title)
                Spacer()
                Text("\(self.movie.releaseYear)")
            }
        }
    }
}

This answer is just right and something I wish I had had when I was learning about it. The example works like a charm.

Now, let’s see if it can help with transitioning from UIKit to SwiftUI. 

I provided a UIKit view and asked ChatGPT to convert it to SwiftUI. I  honestly didn’t expect anything.

This is what I provided:

	class WarningView: UIView {

    func setText(_ text: String) {
        label.text = text
    }

    lazy var warningImage: UIImageView = {
        let imageView = UIImageView(image: UIImage.icWarning)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    lazy var label: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.textColor = UIColor.black
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.system(with: 13, fontWeight: .medium)
        return label
    }()

    lazy var stackView: UIStackView = {
        let stackView = UIStackView()
        stackView.spacing = 16
        stackView.axis = .horizontal
        stackView.alignment = .top
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.addArrangedSubview(warningImage)
        stackView.addArrangedSubview(label)
        return stackView
    }()

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        addSubview(stackView)
        self.backgroundColor = .white

        NSLayoutConstraint.activate([
            warningImage.widthAnchor.constraint(equalToConstant: 24),
            stackView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
            stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16)
        ])
    }

}

And this is what I got in return:

	struct WarningView: View {
    var text: String

    var body: some View {
        HStack(spacing: 16) {
            Image(systemName: "exclamationmark.triangle")
                .resizable()
                .frame(width: 24, height: 24)
                .aspectRatio(contentMode: .fit)
            Text(text)
                .font(.system(size: 13, weight: .medium))
                .foregroundColor(.black)
                .lineLimit(0)
        }
        .padding(16)
        .background(Color.white)
    }
}

This is mindblowing on so many levels. ChatGPT understands UIKit APIs and how the methods translate into UI. It correctly translates UIKit constraints into SwiftUI declaratively defined views with added frames, paddings, and spacings. This can be a great starting point for anyone transitioning from UIKit to the SwiftUI world.

Fixing bugs and problems

Here comes the fun part. Let’s play with our favorites – bugs and pain points, and see if ChatGPT can address them correctly and help us out.

To start with, I chose one common mistake many rookies make in SwiftUI. They apply a frame modifier to an Image view, but it just won’t resize to the given frame. 

When starting out with SwiftUI, I always struggled with this part, so I wanted to see how long the chatbot would take to solve it.

I asked:

Why won’t my image be resized to 50×50 with this code?

	HStack {
    movie.posterImage
        .frame(width: 50, height: 50)
    Text(movie.title)
    Spacer()
    Text("\(movie.releaseYear)")
}

This is how ChatGPT responded:

The `frame(width:height)` modifier sets the size of the view’s frame, but it does not affect the size of the view’s content. In this case, the `posterImage` view is not resized to fit within the frame, so it will be displayed in its original size. 

To resize the image to fit within the frame, you will need to use the `resizable()`modifier in combination with the `frame(width:height:)` modifier. The `resizable()`modifier adjusts the size of the view’s content to fit within the frame, while the `frame(width:height:)` modifier sets the size of the frame. 

Here’s how you can use these modifiers to resize the image to 50×50:

	HStack {
    movie.posterImage
        .resizable()
        .frame(width: 50, height: 50)
    Text(movie.title)
    Spacer()
    Text("\(movie.releaseYear)")
}

This answer is completely correct, and I really like the explanation. ChatGPT explains in detail why this approach is wrong and what SwiftUI does in the background. This particular issue is very hard to find in the official documentation, or it’s far less structured. When you’re learning about SwiftUI, ChatGPT’s answers are much more efficient and effective.

Learning any new technology can be painful at first, but SwiftUI is particularly known to have a steep learning curve. In the following example, I wanted to check whether ChatGPT can help. Building a UI, you’ll often want to create a screen on your own. It’s really hard to break the UI in SwiftUI, but I gave it my best shot. I tried to achieve a view with a yellow background and some text between two images, but I completely butchered it. So let’s see if ChatGPT can help me get back on track.

I asked:

Can you make this code work? I want to show vertically aligned text in between image views, and everything should have a yellow background.

	struct ConfusingView: View {

    var body: some View {
        ZStack {
            Rectangle()
            Text("Mr. Worldwide")
        }
        VStack {
            Image(systemName: "globe")
            Image(systemName: "globe")
        }
    }
}

The first solution it came up with didn’t quite work.

Maybe my requirements were not clear, so I tried correcting them.

This was my follow-up prompt:

I don’t want images horizontally aligned, I want them vertically aligned with text, so that one image is above the text and one is below.

This is the code ChatGPT provided:

	struct ConfusingView: View {
    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(.yellow)
            VStack {
                Image(systemName: "globe")
                Text("Mr. Worldwide")
                Image(systemName: "globe")
            }
        }
    }
}

This is exactly what I wanted! The chatbot can add missing lines of code, adjust the existing ones and remove the unnecessary ones. When asked politely, it seems. In this case, it needed a little more explanation to perform what I intended, but it still feels unreal that it can do so in a matter of seconds.

Bonus: Fun with ChatGPT

Before we conclude this article, I wanted to test ChatGPT’s lyrical abilities using an absurd theme. So here’s a song about SwiftUI written by ChatGPT. Eminem, step down, there’s a new AI on the block.

I’ve been coding for so long

With UIkit, it felt so wrong

But then I found a shining light

With SwiftUI, things felt just right

No more storyboards, no more fuss

Just simple code, that’s not a cuss

With modifiers and bindings too

This framework is really new

Chorus:

SwiftUI, SwiftUI

Making apps is a breeze

SwiftUI, SwiftUI

Making code is a breeze

It’s not just for iOS, it’s for Mac too

Apple’s future, it’s all brand new

With power of swift and UI design

We’ll build apps, that’s one of a kind

ChatGPT proves its worth

We can all agree that this was fun and mind-boggling at the same time. Using ChatGPT in these scenarios feels like the future of coding and learning, and it can be deemed a pretty accurate source. 

The popular text generator is a great starting point and can definitely be your right hand when learning SwiftUI. On some occasions, it still requires previous knowledge of certain SwiftUI concepts so you can articulate your prompts correctly. 

However, ChatGPT really shines in explaining the code. When prompted to provide more thorough explanations, it gave detailed and correct responses for the most part.

Who knows, maybe it will be able to write articles reviewing its own work, such as this one, in the future.