Vibe coding на SwiftUI + Qwen. Как c помощью ИИ сделать простое TODO-приложение на SwiftUI
Искусственный интеллект на сегодняшний день играет важную и быстро растущую роль в разработке программного обеспечения. Его использование охватывает множество аспектов, от автоматизации задач до помощи в принятии решений.
1. Генерация кода
AI-ассистенты по написанию кода , такие как GitHub Copilot, Amazon CodeWhisperer, Tabnine и др., помогают разработчикам:
Автоматически генерировать функции.
Заполнять шаблоны.
Предлагать варианты завершения кода.
Обучены
2. Тестирование и отладка
ИИ используется для:
Генерации тестовых сценариев.
Поиска багов и уязвимостей в коде.
Автоматического исправления ошибок.
Инструменты вроде DeepCode, Snyk, CodiumAI
3. Автоматизация документирования
Системы ИИ могут:
Автоматически создавать документацию к коду.
Писать комментарии.
Генерировать описание API и примеры использования.
4. Анализ требований и планирование проектов
ИИ помогает при:
Переводе пользовательских требований в технические спецификации.
Оценке трудозатрат.
Управлении задачами и приоритетами (например, в Jira + AI).
5. UI/UX дизайн и прототипирование
Инструменты на основе ИИ позволяют:
Преобразовывать текстовые описания в макеты интерфейсов.
Генерировать дизайны.
Создавать прототипы приложений без участия человека.
6. DevOps и автоматизация CI/CD
ИИ применяется в:
Анализе логов и предсказании сбоев.
Автоматической оптимизации процессов деплоя.
Мониторинге производительности и рекомендациях по улучшению.
7. Безопасность и обнаружение угроз
ИИ помогает:
Обнаруживать подозрительное поведение в системе.
Выявлять уязвимости в коде.
Реагировать на атаки в реальном времени.
8. Low-code / No-code платформы с ИИ
Современные low-code платформы (например, Microsoft Power Apps, Bubble, Retool) всё чаще используют ИИ для:
Генерации логики приложений по описанию.
Упрощения создания MVP без глубоких технических знаний.
9. Персонализация и адаптивность продуктов
ИИ используется в финальных продуктах, особенно в:
Рекомендательных системах.
Адаптации интерфейса под пользователя.
Чат-ботах и голосовых помощниках.
По некоторым прогнозам К 2030 году ожидается, ИИ будет использоваться почти во всех этапах разработки ПО.
Возможно появление полностью автономных агентов , способных самостоятельно создавать приложения по текстовому описанию.
Однако, человеческий контроль и экспертиза останутся важными для проверки качества, безопасности и соответствия требованиям.
Я решил проверить на сколько уже сейчас с помощью ИИ возможно написать простое приложение по текстовому описанию имея лишь минимальные знания программирования.
Для проекта я выбрал SwiftUI так как это современный декларативный фреймворк Apple для создания пользовательских интерфейсов. Он позволяет писать меньше кода и быстрее создавать приложения.
В качестве ИИ ассистента я выбрал Qwen так как он имеет бесплатную версию и доступен через вэб-интерфейс.
Я создал проект в Xcode, открыл https://chat.qwen.ai и написал первый промпт: «Ты опытный iOS разработчик. Напиши простейшее TODO-List приложение на SwiftUI»
Немного подумав ИИ выдал следующий код:
import SwiftUI
struct ContentView: View {
@State private var todos: [Todo] = []
@State private var newTodoText: String = ""
var body: some View {
NavigationView {
VStack {
HStack {
TextField("New task", text: $newTodoText)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: addTodo) {
Image(systemName: "plus")
.foregroundColor(.blue)
}
}
.padding()
List {
ForEach($todos) { $todo in
HStack {
Button {
todo.completed.toggle()
} label: {
Image(systemName: todo.completed ? "checkmark.circle.fill" : "circle")
.foregroundColor(todo.completed ? .green : .gray)
}
Text(todo.title)
.strikethrough(todo.completed, color: .gray)
.foregroundColor(todo.completed ? .gray : .primary)
}
}
.onDelete(perform: deleteTodos)
}
}
.navigationTitle("TODO List")
}
}
func addTodo() {
guard !newTodoText.trimmingCharacters(in: .whitespaces).isEmpty else { return }
todos.append(Todo(title: newTodoText))
newTodoText = ""
}
func deleteTodos(at offsets: IndexSet) {
todos.remove(atOffsets: offsets)
}
}
// MARK: - Models
struct Todo: Identifiable {
let id = UUID()
var title: String
var completed: Bool = false
}
// MARK: - Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Должен отметить, что скопировав код и вставив его в Xcode я получил готовое рабочее приложение. Править и дописывать ничего не пришлось.
Результат представлял собой одноэкранное приложение со строкой ввода и кнопкой +, чтобы добавлять дела в свой список и ниже сам список с названием пункта и чекбоксом.
При нажатии пункт отмечался как выполненный. Текст зачеркивался, а чек-бокс становился зеленым.
Я решил немного расширить приложение и добавить для каждого пункта из списка дел экран деталей.
Мой второй промпт был таким: «Сделай так чтобы при нажатии на айтем в списке происходил переход на экран деталей»
ИИ сгенерировал новый год, добавив возможность перехода на экран деталей.
import SwiftUI
struct ContentView: View {
@State private var todos: [Todo] = []
@State private var newTodoText: String = ""
var body: some View {
NavigationView {
VStack {
HStack {
TextField("New task", text: $newTodoText)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: addTodo) {
Image(systemName: "plus")
.foregroundColor(.blue)
}
}
.padding()
List {
ForEach($todos) { $todo in
NavigationLink(destination: DetailView(todo: $todo)) {
HStack {
Button {
todo.completed.toggle()
} label: {
Image(systemName: todo.completed ? "checkmark.circle.fill" : "circle")
.foregroundColor(todo.completed ? .green : .gray)
}
Text(todo.title)
.strikethrough(todo.completed, color: .gray)
.foregroundColor(todo.completed ? .gray : .primary)
}
}
}
.onDelete(perform: deleteTodos)
}
}
.navigationTitle("TODO List")
}
}
func addTodo() {
guard !newTodoText.trimmingCharacters(in: .whitespaces).isEmpty else { return }
todos.append(Todo(title: newTodoText))
newTodoText = ""
}
func deleteTodos(at offsets: IndexSet) {
todos.remove(atOffsets: offsets)
}
}
// MARK: - Detail View
struct DetailView: View {
@Binding var todo: Todo
var body: some View {
Form {
TextField("Task", text: $todo.title)
Toggle("Completed", isOn: $todo.completed)
}
.navigationTitle("Edit Task")
}
}
// MARK: - Models
struct Todo: Identifiable {
let id = UUID()
var title: String
var completed: Bool = false
}
// MARK: - Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
У Qwen есть довольно полезная опция. Он описывает, какие изменения он внес в код.
🧠 Что изменилось?NavigationLink добавлен для каждой строки списка:
Открывает
DetailView
, передавая$todo
по ссылке (через@Binding
).
DetailView
:
Позволяет редактировать заголовок задачи.
Переключать статус выполнения.
Редактирование происходит "на лету" , так как используется
@Binding
.
В итоге получился ожидаемый результат. Главный экран остался без изменений.
Экран деталей на котором мы можем изменить название айтема и отметить отметить его как выполненный или наоборот с помощью свитчера.
Отметим пункт как завершенный
Главный экран с завершенной задачей
Изменим название
Результат
Все работает.
Теперь чекбокс перед названием айтема кажется лишним так как мы его не используем.Попробуем избавиться от него. Так как цель написать приложение на 100% с помощью ии, то и все правки поручим ИИ.
Мой промпт для удаления чекбокса был следующим: «Убери круг перед названием пункта и если пункт выполнен то изменяй цвет его текста на зеленый»
Немного подумав Qwen отчитался о проделанной работе:
И выдал измененный код
import SwiftUI
struct ContentView: View {
@State private var todos: [Todo] = []
@State private var newTodoText: String = ""
var body: some View {
NavigationView {
VStack {
HStack {
TextField("New task", text: $newTodoText)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: addTodo) {
Image(systemName: "plus")
.foregroundColor(.blue)
}
}
.padding()
List {
ForEach($todos) { $todo in
NavigationLink(destination: DetailView(todo: $todo)) {
Text(todo.title)
.foregroundColor(todo.completed ? .green : .primary)
.strikethrough(todo.completed, color: todo.completed ? .green : nil)
}
}
.onDelete(perform: deleteTodos)
}
}
.navigationTitle("TODO List")
}
}
func addTodo() {
guard !newTodoText.trimmingCharacters(in: .whitespaces).isEmpty else { return }
todos.append(Todo(title: newTodoText))
newTodoText = ""
}
func deleteTodos(at offsets: IndexSet) {
todos.remove(atOffsets: offsets)
}
}
// MARK: - Detail View
struct DetailView: View {
@Binding var todo: Todo
var body: some View {
Form {
TextField("Task", text: $todo.title)
Toggle("Completed", isOn: $todo.completed)
}
.navigationTitle("Edit Task")
}
}
// MARK: - Model
struct Todo: Identifiable {
let id = UUID()
var title: String
var completed: Bool = false
}
// MARK: - Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Как обычно подсветил что было сделано
На этот раз снова получился тот результат, который и ожидался. Пункт списка дел без чекбокса спереди.
При переводе пункта в разряд выполненных
Текст меняется на зеленый и зачеркивается
«Продолжим развивать приложение» решил я и задал следующий промпт: «Сделай бэкграунд основного экрана оранжевым»
На этот раз ИИ не стал регенерить код полностью, а выдал краткий ответ:
На первый взгляд получили как раз то, что хотели
Но если добавить дело в список, то получим не совсем тот результат, который ожидался.
Моим принципиальным решением было не исправлять код самому, а проверить то на сколько сам ИИ сможет написать приложение по текстовому описанию.
После нескольких запросов на исправление текущего кода и получение желаемого результата, при котором фон списка так же должен быть всегда оранжевым стабильно работающего решения получить от ИИ не удалось.
Тут сыграл момент с галлюцинациями ИИ, когда ИИ дает уверенный ответ, но на практике он оказывается не верным.
Отложив вопрос с фоном списка дел, решил дополнить приложение еще одной небольшой фичей.
Мой промпт выглядел следующим образом: «Дополни код так чтобы если выполненных пунктов больше чем не выполненных фон экрана становился светло-зеленым»
ИИ уже знакомо отозвался:
И выдал код:
import SwiftUI
struct ContentView: View {
@State private var todos: [Todo] = []
@State private var newTodoText: String = ""
// 🟢 Вычисляемое свойство для определения цвета фона
var backgroundColor: Color {
let completedCount = todos.filter { $0.completed }.count
let uncompletedCount = todos.count - completedCount
return completedCount > uncompletedCount ? Color.green.opacity(0.3) : Color.orange.opacity(0.3)
}
var body: some View {
NavigationView {
VStack {
HStack {
TextField("New task", text: $newTodoText)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: addTodo) {
Image(systemName: "plus")
.foregroundColor(.blue)
}
}
.padding()
List {
ForEach($todos) { $todo in
NavigationLink(destination: DetailView(todo: $todo)) {
Text(todo.title)
.foregroundColor(todo.completed ? .green : .primary)
.strikethrough(todo.completed, color: todo.completed ? .green : nil)
}
}
.onDelete(perform: deleteTodos)
}
.listStyle(PlainListStyle()) // Убираем стандартный стиль списка
.background(Color.clear) // Делаем фон списка прозрачным, чтобы он не мешал основному фону
}
.background(
ZStack {
backgroundColor
.ignoresSafeArea()
}
)
.navigationTitle("TODO List")
}
}
func addTodo() {
guard !newTodoText.trimmingCharacters(in: .whitespaces).isEmpty else { return }
todos.append(Todo(title: newTodoText))
newTodoText = ""
}
func deleteTodos(at offsets: IndexSet) {
todos.remove(atOffsets: offsets)
}
}
// MARK: - Detail View
struct DetailView: View {
@Binding var todo: Todo
var body: some View {
Form {
TextField("Task", text: $todo.title)
Toggle("Completed", isOn: $todo.completed)
}
.navigationTitle("Edit Task")
}
}
// MARK: - Model
struct Todo: Identifiable {
let id = UUID()
var title: String
var completed: Bool = false
}
// MARK: - Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Отметим два пункта из трех как выполненные и получаем зеленый бэкграунд
Удалим один выполненный пункт
Цвет фона вновь станет оранжевым, так как выполненных пунктов не больше чем не выполненных. Все соответствует запросу.
Какие выводы можно сделать исходя из данного эксперемента и практически ежедневного применения ИИ в работе?
Использование искусственного интеллекта в программировании уже сегодня позволяет значительно ускорить и упростить процесс разработки. ИИ отлично справляется с рутинными и стандартными задачами — от генерации простого кода до автоматического написания тестов и документации. Однако при работе над более сложными и нетиповыми задачами , результаты, предоставляемые ИИ, зачастую требуют внимательного контроля, доработки и проверки со стороны опытных разработчиков .
Одной из ключевых проблем остаются галлюцинации ИИ — ситуация, когда система уверенно предлагает логически выглядящие, но фактически неверные или неработающие решения. Это делает невозможным полное доверие к выводам модели без участия человека.
Таким образом, на данном этапе развития технологии ИИ является мощным вспомогательным инструментом , а не самостоятельным разработчиком. Его эффективность напрямую зависит от квалификации специалиста, способного оценить качество сгенерированного кода и вовремя исправить возможные ошибки.