起きている問題
SwiftUIとFirebaseのrealtimedatabaseを使用して投稿アプリを開発しています。
新規ユーザーで一番初めの投稿だけ表示されません。
状況としては下記の通りです。
・新規ユーザーの一番初めの投稿だけ一覧に表示されない
・アプリを再起動させると一番初めに投稿したものが表示されている
・再起動後はリアルタイムで投稿と表示がされていく
発生している問題・エラーメッセージ
プレビューではエラーメッセージは出力されていませんでした。
該当のソースコード
■投稿一覧画面
PostListView.swift
1 2import SwiftUI 3import Firebase 4 5 6struct Post: Identifiable, Hashable { 7 var id: String// = UUID().uuidString 8 var icon: String 9: 10 let icon = value["icon"] as? String, 11 let id = value["id"] as? String else { 12 return nil 13 } 14 15 self.id = id 16: 17 self.icon = icon 18 } 19} 20 21class TimeData: ObservableObject { 22 @Published var totalTime: [String: Int] = [:] 23} 24 25class PostsViewModel: ObservableObject { 26 @Published var posts: [Post] = [] 27 let userID: String = AuthManager.shared.user?.uid ?? "" 28 private let databaseRef = Database.database().reference() 29 30 init() { 31 fetchPosts() 32 } 33 34 private func fetchPosts() { 35 databaseRef.child("Posts").observe(.value) { snapshot in 36 var newPosts: [Post] = [] 37 for child in snapshot.children { 38 if let snapshot = child as? DataSnapshot, 39 let post = Post(snapshot: snapshot) { 40 newPosts.append(post) 41 } 42 } 43 DispatchQueue.main.async { 44 self.posts = newPosts.sorted(by: { $0.createdAt > $1.createdAt }) 45 } 46 } 47 } 48} 49 50struct PostListView: View { 51 @State var posts: [Post] = [] 52: 53: 54 55 }.padding() 56 .accentColor(Color(red: 0.35, green: 0.35, blue: 0.35, opacity: 1)) 57 }) 58 } 59 } 60 Spacer() 61 .onAppear { 62 databaseRef.child("Posts").observe(.value) { snapshot in 63 var newPosts: [Post] = [] 64 for child in snapshot.children { 65 if let snapshot = child as? DataSnapshot, 66 let post = Post(snapshot: snapshot) { 67 newPosts.append(post) 68 } 69 } 70 posts = newPosts.sorted(by: { $0.createdAt > $1.createdAt }) 71 selectedPost = getOldestPost(posts: posts) 72 } 73 : 74 } 75 } 76 77 }.background(Color(red: 0.95, green: 0.95, blue: 0.97, opacity: 1.0)) 78 .frame(width: UIScreen.main.bounds.width) 79 // .navigationBarTitle("積み上げリスト", displayMode: .inline) 80 .overlay( 81: 82 Spacer() 83 Button(action: { 84 self.showAnotherView_post = true 85 }, label: { 86 Image(systemName: "plus") 87 .foregroundColor(.white) 88 .font(.system(size: 24)) // --- 4 89 }).frame(width: 60, height: 60) 90 .background(Color(red: 0.2, green: 0.68, blue: 0.9, opacity: 1.0)) 91 .cornerRadius(30.0) 92 .shadow(color: Color(.black).opacity(0.2), radius: 8, x: 0, y: 4) 93 .sheet(isPresented: $showAnotherView_post, content: { 94 95 PostAdd(showAnotherView_post: PostListView.$dummyShowAnotherView) 96 }) 97 .padding() 98 } 99 } 100 } 101 } 102 ) 103 }.background(Color(red: 0.95, green: 0.95, blue: 0.97, opacity: 1.0)) 104 } 105 .navigationViewStyle(StackNavigationViewStyle()) 106 } 107 108 private func progressValue(for post: Post) -> Double { 109 guard let totalTimeForPost = timeData.totalTime[post.id] else { 110 return 0.0 111 } 112 113 Text("\(Double(totalTimeForPost / 3600))") 114 115 return Double(totalTimeForPost) / Double(post.goalHours * 3600) 116 } 117 118 func getOldestPost(posts: [Post]) -> Post? { 119 return posts.sorted(by: { $0.createdAt < $1.createdAt }).first 120 } 121} 122 123 124 125 126fileprivate struct AnotherView: View { 127 128 var postID: String 129 var postTitle: String 130 131 var body: some View { 132 TimeView(postID: postID,postTitle: postTitle, isHStackVisible: false) 133 134 //PrivacyView() 135 } 136 137} 138 139struct CustomProgressViewStyle: ProgressViewStyle { 140 func makeBody(configuration: Configuration) -> some View { 141: 142 } 143} 144 145 146struct nextView: View { 147 @Environment(\.dismiss) private var dismiss 148 var postID: String 149 var postTitle: String 150 151 var body: some View { 152 NavigationView { 153 TimeView(postID: postID,postTitle: postTitle) 154 .navigationTitle("コメント一覧") 155 .navigationBarItems(leading: Button("戻る", action: { dismiss() })) 156 } 157 } 158} 159 160struct PostListView_Previews: PreviewProvider { 161 static var previews: some View { 162 PostListView() 163 } 164} 165
■投稿追加画面
PostAdd.swift
1import SwiftUI 2import Firebase 3 4struct IconInfo: Identifiable { 5 let id = UUID() 6 let name: String 7 let systemImageName: String 8} 9 10struct PostAdd: View { 11 @State var posts: [Post] = [] 12: 13 IconInfo(name: "その他", systemImageName: "questionmark"), 14 ] 15 var body: some View { 16 HStack{ 17 Button(action:{ 18 self.presentationMode.wrappedValue.dismiss() // この行を修正 19 }){ 20 Text("閉じる") 21 } 22 .padding() 23 Spacer() 24 Text("積み上げ目標を追加する") 25 Spacer() 26 Button(action:{ addPost() 27 self.showAnotherView_post = false // この行を追加 28 self.presentationMode.wrappedValue.dismiss() 29 }){ 30 Text("投稿する") 31 } 32 .padding() 33 } //閉じるボタンと投稿する 34 //.padding() 35 .background(Color(red: 0.2, green: 0.68, blue: 0.9, opacity: 1.0)) 36 .foregroundColor(.white) 37 : 38: 39 } 40 41 func addPost() { 42 let databaseRef = Database.database().reference() 43 let postRef = databaseRef.child("Posts").childByAutoId() 44 let post = ["id": postRef.key!, 45 "title": postText, 46 "icon": selectedIcon?.systemImageName ?? "", // ここも修正 47 "body": body_text, 48 "goalHours": Int(progressValue), 49 "userID": userID, 50 "createdAt": Date().timeIntervalSince1970] as [String : Any] 51 postRef.setValue(post) { error, _ in 52 if let error = error { 53 print(error.localizedDescription) 54 } else { 55 print("コメントが投稿されました") 56 postText="" 57 selection_post = "" 58 goalHours = 1 59 } 60 } 61 } 62} 63 64struct PostAdd_Previews: PreviewProvider { 65 @State static private var dummyShowAnotherView = false 66 67 static var previews: some View { 68 PostAdd(showAnotherView_post: $dummyShowAnotherView) 69 } 70} 71
試したこと
fetchPosts関数を投稿機能に追加して、投稿時に再取得を行ったのですが表示されませんでした。
func fetchPosts() { databaseRef.child("Posts").observe(.childAdded) { snapshot in if let post = Post(snapshot: snapshot) { DispatchQueue.main.async { self.posts.append(post) self.posts.sort(by: { $0.createdAt > $1.createdAt }) } } } } func addPost() { let databaseRef = Database.database().reference() let postRef = databaseRef.child("Posts").childByAutoId() let post = ["id": postRef.key!, "title": postText, "icon": selectedIcon?.systemImageName ?? "", // ここも修正 "body": body_text, "goalHours": Int(progressValue), "userID": userID, "createdAt": Date().timeIntervalSince1970] as [String : Any] postRef.setValue(post) { error, _ in if let error = error { print(error.localizedDescription) } else { print("コメントが投稿されました") postText="" selection_post = "" goalHours = 1 fetchPosts() //ここを追加 } } }
補足情報(FW/ツールのバージョンなど)
swift-driver version: 1.75.2
Xcode 14.3
Build version 14E222b
あなたの回答
tips
プレビュー