I have a dictionary postsAuthorsProfilePicturesURLs[String: URL] that stores post ID along with corresponding URL for profile picture of post author. I initialize it in ViewModel initially with:
@Published var postsAuthorsProfilePicturesURLs: [String: URL] = [:]
Posts IDs are fetched from firebase in ViewModel. For testing purposes, to every post id key I assign the same value of valid url for some image in the same method in ViewModel.
The problem is in the view itself. In ForEach loop I'm trying to display posts, with their details, along with profilePictures of post authors. For this I'm using AsyncImage.
I have the following code:
AsyncImage(url: homeViewModel.postsAuthorsProfilePicturesURLs[post.id]!) { phase in
if let image = phase.image {
image
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
.frame(width: screenWidth * 0.15, height: screenHeight * 0.15)
} else {
Image(uiImage: UIImage(named: "blank-profile-hi")!)
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
.frame(width: screenWidth * 0.15, height: screenHeight * 0.15)
}
}
and it works correctly rendering async image downloaded from the url. I want however to unwrap the optional homeViewModel.postsAuthorsProfilePicturesURLs[post.id] in the safer way. For example like this:
if let profilePictureURL = homeViewModel.postsAuthorsProfilePicturesURLs[post.id] {
AsyncImage(url: profilePictureURL) { phase in
if let image = phase.image {
image
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
.frame(width: screenWidth * 0.15, height: screenHeight * 0.15)
} else {
Image(uiImage: UIImage(named: "blank-profile-hi")!)
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
.frame(width: screenWidth * 0.15, height: screenHeight * 0.15)
}
}
}
Although this change does not allow the app to build. The same problem exists when nil checking is used:
if homeViewModel.postsAuthorsProfilePicturesURLs[post.id] != nil
I don't know how to handle this.
EDIT:
Actually, I tried breaking up the expression into distinct sub-expressions by commenting the parts of the whole View and it turned out that the part with AsyncImage is completely correct. What's not correct is the part with .confirmationDialog which I had attached to different part of this View. Now the app won't compile because of this confirmationDialog
.confirmationDialog("What", isPresented: $showPostOptions) {
Button("Edit") {
sheetManager.postID = post.id
sheetManager.postText = post.text
sheetManager.whichSheet = .editView
sheetManager.showSheet.toggle()
}
Button("Delete", role: .destructive) {
self.homeViewModel.deletePost(postID: post.id)
}
}
Commenting either the part of code with AsyncImage or the .confirmationDialog enables the app to build.
CodePudding user response:
works well for me in my simple test. Are you sure you have a URL in your
@Published var postsAuthorsProfilePicturesURLs: [String: URL] = [:] and not a
Optional URL.
Here is my test code:
class ProfileManager: ObservableObject{
@Published var postsAuthorsProfilePicturesURLs: [String: URL] = [:]
}
struct ContentView: View {
@StateObject var homeViewModel = ProfileManager()
var body: some View {
if let profilePictureURL = homeViewModel.postsAuthorsProfilePicturesURLs["first"] {
AsyncImage(url: profilePictureURL) { phase in
if let image = phase.image {
image
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
} else {
Image(uiImage: UIImage(systemName: "globe")!)
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 50))
}
}
}
Text("testing")
.onAppear {
if let url = URL(string:"https://upload.wikimedia.org/wikipedia/commons/e/ef/Red-billed_gull,_Red_Zone,_Christchurch,_New_Zealand.jpg") {
homeViewModel.postsAuthorsProfilePicturesURLs = ["first":url] // <-- here a URL not a URL?
}
}
}
}
CodePudding user response:
I managed to fix the problem by breaking my one view, where the problem was, into 3 smaller subviews which I connected in the main view. So it seems both .confirmationDialog modifier and optional unwrapping were correct. My previous view must had been too big.
