my app have some issues: when I restart iPhone my tasks and notes in app is disappeared. same situation when I update new version of my app. my app has synchronization via iCloud through all Apple devices (iPad, Mac, iPhone)
my app is distributing in App Store:
below code of my app, tell me please some ways to do for get 100% right syntonization via iCloud without bugs and missing content:
ContentView.swift:
import SwiftUI
struct ContentView: View {
@State private var currentTodo = ""
@State private var currentNoteContent = ""
@State private var expandedTaskId: UUID?
@State private var isShowingNotes = false
@State private var showingAlert = false
@State private var alertMessage = ""
@StateObject private var taskManager = TaskManager()
// Добавление задачи
private func addTodoAction() {
guard !currentTodo.trimmingCharacters(in: .whitespaces).isEmpty else {
alertMessage = "Введите текст задачи"
showingAlert = true
return
}
taskManager.addTodo(todo: currentTodo.trimmingCharacters(in: .whitespaces))
currentTodo = ""
}
var body: some View {
NavigationStack {
VStack {
// 1. Поле ввода и кнопка
HStack {
TextField("Write task here and click the right button", text: $currentTodo)
.textFieldStyle(RoundedBorderTextFieldStyle())
.onSubmit { addTodoAction() }
Button(action: addTodoAction) {
Image(systemName: "pencil.tip.crop.circle.badge.plus")
}
.padding(.leading, 5)
}
.padding()
// 2. Список задач
List {
ForEach($taskManager.todos, id: \.id) { $todo in
VStack(alignment: .leading) {
HStack(alignment: .center) {
VStack(alignment: .leading, spacing: 4) {
Text(todo.todo)
.lineLimit(1)
HStack {
Slider(
value: $todo.progress,
in: 0...100,
step: 1
) { isEditing in
if !isEditing {
taskManager.updateProgress(for: todo.id, progress: todo.progress)
}
}
.frame(width: 100)
Text("\(Int(todo.progress))%")
.font(.caption)
.foregroundColor(.gray)
.frame(width: 40, alignment: .leading)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
Button(action: {
todo.subtasks.append(Subtask(title: "New subtask"))
expandedTaskId = todo.id
}) {
Image(systemName: "plus.circle")
.foregroundColor(.blue)
}
.buttonStyle(PlainButtonStyle())
.padding(.leading, 4)
Button(action: {
expandedTaskId = (expandedTaskId == todo.id) ? nil : todo.id
}) {
Image(systemName: expandedTaskId == todo.id ? "chevron.down" : "chevron.right")
.foregroundColor(.gray)
.imageScale(.medium)
}
.buttonStyle(PlainButtonStyle())
.contentShape(Rectangle())
.frame(width: 24, height: 24)
}
.padding(.vertical, 6)
if expandedTaskId == todo.id && !todo.subtasks.isEmpty {
ForEach($todo.subtasks, id: \.id) { $subtask in
HStack {
Button(action: {
taskManager.toggleSubtaskCompletion(for: todo.id, subtaskId: subtask.id)
}) {
Image(systemName: subtask.isCompleted ? "checkmark.square.fill" : "square")
.foregroundColor(subtask.isCompleted ? .blue : .gray)
}
.buttonStyle(PlainButtonStyle())
TextField("Подзадача", text: $subtask.title)
.disabled(subtask.isCompleted)
.foregroundColor(subtask.isCompleted ? .gray : .primary)
.padding(.leading, 4)
.onChange(of: subtask.title) { _ in
taskManager.scheduleSave()
}
}
.padding(.leading, 28)
.padding(.vertical, 4)
}
.padding(.top, 4)
}
}
.padding(.horizontal, -8)
}
.onDelete(perform: { offsets in
taskManager.deleteTodo(at: offsets)
})
// 3. Кнопка Notes
Button(action: {
isShowingNotes = true
}) {
Text("Notes")
.font(.headline)
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(10)
}
.padding(.horizontal)
.padding(.top, 10)
// 4. Индикатор загрузки
if taskManager.isSyncing {
ProgressView("Downloading..")
.progressViewStyle(CircularProgressViewStyle())
.padding()
}
}
.navigationTitle("Just To Do It List")
}
.onAppear {
DataManager.shared.ensureTodosFileExists()
DataManager.shared.taskManager = taskManager
DataManager.shared.startMonitoringTodosChanges()
taskManager.loadTodos()
// Принудительно перезагружаем заметки при открытии
DataManager.shared.loadNotes { result in
switch result {
case .success(let content):
currentNoteContent = content ?? ""
case .failure(let error):
alertMessage = "Error loading notes: \(error.localizedDescription)"
showingAlert = true
}
}
// Запускаем мониторинг изменений (если ещё не запущен)
DataManager.shared.startMonitoringNotesChanges()
DataManager.shared.startMonitoringTodosChanges()
}
.navigationDestination(isPresented: $isShowingNotes) {
NotesEditView(
noteContent: $currentNoteContent,
onSave: { savedText in
currentNoteContent = savedText
DataManager.shared.saveNotes(
content: savedText,
completion: { error in
if let error = error {
alertMessage = "Error: \(error.localizedDescription)"
showingAlert = true
}
}
)
}
)
.onDisappear {
// Принудительно сохраняем текущие заметки при закрытии
DataManager.shared.saveNotes(
content: currentNoteContent,
completion: { error in
if let error = error {
alertMessage = "Error via closure: \(error.localizedDescription)"
showingAlert = true
} else {
print("✅ Notes saved via closure")
}
}
)
isShowingNotes = false
}
}