My Memory Graph shows 2 FeedViewModels even though it should only be one since I only have 1 Feed created in Firebase
If i printObject feedViewModel.text in the init block breakpoint in my FeedRow it shows -> This is a firebase text 5
But when i printObject feedViewModel.text in the breakpoint where the view actually displays the text it shows -> This is a firebase text 4
Here is my function in the firebase repository: `func fetchAllFeeds(completion: @escaping (Result<[Feed], FirebaseError>) -> Void) { self.feedIdsListener = FirebaseManager.shared.firestore.collection("feeds").addSnapshotListener { querySnapshot, error in if let error { print("Fetch feeds failed: (error)") completion(.failure(.unknown(error))) return }
guard let documents = querySnapshot?.documents else {
print("Query Snapshot has no documents")
completion(.failure(.collectioNotFound))
return
}
let allFeeds = documents.compactMap { document in
try? document.data(as: Feed.self)
}
completion(.success(allFeeds))
}
}`
Here is the function in my FeedsViewModel that generates my [FeedViewModel] `private func fetchAllFeeds() { feedRepository.fetchAllFeeds() { [weak self] result in switch result { case .success(let allFeeds): if let user = self?.user { self?.feeds = allFeeds.compactMap { FeedViewModel($0, withUser: user) } self?.feeds.sort(by: { $0.updatedAt > $1.updatedAt })
if let feeds = self?.feeds {
self?.followedFeeds = feeds.filter { user.following.contains($0.creator) }
self?.ownFeeds = feeds.filter { $0.creator == user }
self?.usedFeeds = feeds.filter { $0.activeUsers.contains(user) }
}
}
case .failure(let error):
print("Failed fetching feeds: \(error)")
}
}
}`
At this point i generate my FeedRows in my FeedView using the data from the FeedsViewModel
VStack { ForEach(self.feedsViewModel.feeds) { feed in FeedRow(feed) } } .padding(.horizontal)
Here is my FeedRow `struct FeedRow: View {
@EnvironmentObject var authenticationViewModel: AuthenticationViewModel
@StateObject var feedViewModel: FeedViewModel
@State private var showComments = false
@State private var translationActive: Bool = false
private var textIsTranslated: Bool {
feedViewModel.translatedText != nil
}
init(_ feedViewModel: FeedViewModel) {
_feedViewModel = StateObject(wrappedValue: feedViewModel)
}
var body: some View {
VStack(spacing: 8) {
HStack(alignment: .top, spacing: 16) {
ProfilePictureSmall()
VStack(spacing: 8) {
HStack {
Text(self.feedViewModel.creator.realName)
.font(.footnote)
.fontWeight(.semibold)
Spacer()
Button(action: {
}, label: {
Image(systemName: "envelope")
.foregroundStyle(LinearGradient(gradient: Gradient(colors: [.blue, .red]), startPoint: .leading, endPoint: .trailing))
})
}
Text((!self.translationActive ? self.feedViewModel.text : self.feedViewModel.translatedText) ?? "")
.font(.footnote)
.fontWeight(.thin)
.frame(maxWidth: .infinity, alignment: .leading)
HStack(alignment: .bottom, spacing: 16) {
VStack {
Button(action: {
self.feedViewModel.likeFeed()
}, label: {
Image(systemName: "heart")
.foregroundStyle(LinearGradient(gradient: Gradient(colors: [.blue, .red]), startPoint: .leading, endPoint: .trailing))
})
Text(String(self.feedViewModel.likes.count))
.font(.footnote)
.fontWeight(.ultraLight)
}
VStack {
Button(action: {
self.showComments = true
}, label: {
Image(systemName: "text.bubble")
.foregroundStyle(LinearGradient(gradient: Gradient(colors: [.red, .blue]), startPoint: .leading, endPoint: .trailing))
})
Text(String(self.feedViewModel.comments.count))
.font(.footnote)
.fontWeight(.ultraLight)
}
Spacer()
VStack {
Button(action: {
self.translationActive.toggle()
}, label: {
Text(self.textIsTranslated ? (self.translationActive ? "Show original" : "Translate") : "No Translation")
})
.disabled(!self.textIsTranslated)
Text(self.feedViewModel.createdAtString)
.fontWeight(.ultraLight)
}
.font(.footnote)
}
}
}
if !self.feedViewModel.images.isEmpty {
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(alignment: .center) {
ForEach(self.feedViewModel.images, id: \.self) { url in
AsyncImage(
url: URL(string: url),
content: { image in
image
.resizable()
.scaledToFit()
.frame(height: 200)
.clipShape(RoundedRectangle(cornerRadius: 10))
},
placeholder: {
Image(systemName: "network.slash")
}
)
}
}
.padding(.horizontal)
}
.frame(height: 200)
}
Divider()
if !self.feedViewModel.richPreviews.isEmpty {
ForEach(self.feedViewModel.richPreviews) { richLinkPreview in
RichLinkPreviewView(richPreviewViewModel: richLinkPreview)
}
}
}
.sheet(isPresented: $showComments, content: {
CommentsView()
.environmentObject(self.feedViewModel)
.presentationDetents([.medium, .large])
})
.onAppear {
self.feedViewModel.translateText()
}
.onChange(of: self.textIsTranslated) {
if self.textIsTranslated {
self.translationActive = true
} else {
self.translationActive = false
}
}
}
}`
I already tried [weak self] in the function in the FeedsViewModel in hope it helps but it didnt change anything and the memory leak persists
I fixed it by modyfing the code in the FeedRow like this: @EnvironmentObject var authenticationViewModel: AuthenticationViewModel weak var weakFeedViewModel: FeedViewModel? @ObservedObject var feedViewModel: FeedViewModel
@State private var showComments = false
@State private var translationActive: Bool = false
private var textIsTranslated: Bool {
feedViewModel.translatedText != nil
}
init(_ feedViewModel: FeedViewModel) {
weakFeedViewModel = feedViewModel
_feedViewModel = ObservedObject(wrappedValue: weakFeedViewModel ?? feedViewModel)
}