I have a View with a search button in the toolbar. The search button presents a sheet to the user and when he clicks on a result I would like the sheet to be dismissed and a detailView to be opened rather than navigating to the detailView from inside the sheet.
The dismiss part is easy, but how do I open the detailView in the NavigationStack relative to the original View that presented the Sheet?
Post
Replies
Boosts
Views
Activity
I have a View with a search button in the toolbar. The search button presents a sheet to the user and when he clicks on a result I would like the sheet to be dismissed and a detailView to be opened rather than navigating to the detailView from inside the sheet.
The dismiss part is easy, but how do I open the detailView in the NavigationStack relative to the original View that presented the Sheet?
@StateObject private var vm = QuotesViewModelImpl(service: QuotesServiceImpl()) --> Error Here
var body: some View {
Group {
if vm.quotes.isEmpty {
LoadingView(text: "Fetching Quotes")
} else {
List {
ForEach(vm.quotes, id: \.anime) { quote in
QuoteView(quote: quote)
}
}
}
}
.task {
await vm.getRandomQuotes()
}
}
}
Here is the ViewModel:
final class QuotesViewModelImpl: QuotesViewModel {
@Published private(set) var quotes: [Quote] = []
private let service: QuotesService
init(service: QuotesService) async {
self.service = service
}
func getRandomQuotes() async {
do {
self.quotes = try await service.fetchRandomQuotes()
} catch {
print(error)
}
}
}
Text("Hello")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(.primary)
.onTapGesture {
// Some code
}
In this example, there is text and some modifiers. I'd like to know what other modifiers I can use with that specific view. and also what other options I have for each modifier like what other types of fonts there are. How can I get that information using Apple's documentation?
The canvas is giving me an error and the app crashed because of this error:
Fatal error: No ObservableObject of type LocationsViewModel found. A View.environmentObject(_:) for LocationsViewModel may be missing as an ancestor of this view.
Also this is the error from the canvas:
SwiftUI App crashed due to missing environment of type: LocationsViewModel. to resolve this add .environmentObject(LocationsViewModel(...)) to the appropriate preview
Of course that line of code is already there and that error only shows in this swift file alone. other files works peoperly
@main
struct SwiftUI_Map_AppApp: App {
@StateObject private var vm = LocationsViewModel()
var body: some Scene {
WindowGroup {
LocationsView()
.environmentObject(vm) // Any child view will have access to this environment object
}
}
}
LocationsView:
@EnvironmentObject private var vm: LocationsViewModel
var body: some View {
ZStack {
// Content
}
.sheet(item: $vm.sheetLocation) { location in
LocationDetailView(location: location)
}
}
}
struct LocationsView_Previews: PreviewProvider {
static var previews: some View {
LocationsView()
.environmentObject(LocationsViewModel())
}
}
LocationDetailView:
@EnvironmentObject private var vm: LocationsViewModel
let location: Location
var body: some View {
ScrollView {
VStack {
imageSection
.shadow(color: Color.black.opacity(0.3), radius: 20, x: 0, y: 10)
VStack(alignment: .leading, spacing: 16) {
titleSction
Divider()
descriptionSction
Divider()
mapLayer
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
}
}
.ignoresSafeArea()
.background(.ultraThinMaterial)
.overlay(alignment: .leading) {
backButton
}
}
}
struct LocationDetailView_Previews: PreviewProvider {
static var previews: some View {
LocationDetailView(location: LocationsDataService.locations.first!)
.environmentObject(LocationsViewModel()) <- Error here
// as if it's not even there
}
}
LocationsViewModel:
class LocationsViewModel: ObservableObject {
init() {
let locations = LocationsDataService.locations
self.locations = locations
mapLocation = locations.first!
}
In my app, the user can search for an image from a specific API and then click on a button to get that image's url. My question is how to display the image to the user?
ContentView:
@StateObject var dataModel = DataModel()
var body: some View {
			 // Text to display the link of the Image, when clicked on, it opens in Safari:
Text("\(dataModel.imageURL)")
.padding()
.onTapGesture {
let url = URL(string: dataModel.imageURL)
guard let recievedURL = url, UIApplication.shared.canOpenURL(recievedURL) else { return }
UIApplication.shared.open(recievedURL)
}
// TextField where the user enters the search word:
TextField("Search Images...", text: $dataModel.searchTerm)
// After pressing this button, the DataModel fetches the data and presents the url in the text above:
Button(action: {
dataModel.fetchAPI()
}, label: {
Text("Fetch Image")
})
}
The function in DataModel() that fetches the data:
@Published var imageURL = String()
@Published var searchTerm = String()
func fetchAPI() {
guard let url = URL(string:{The url including the searchWord}) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let recievedData = data, error == nil else {
print("ERROR: \(String(describing: error?.localizedDescription))")
return
}
do {
let model = try JSONDecoder().decode(ImageData.self, from: recievedData)
DispatchQueue.main.async {
self.imageURL = model.data.first?.url ?? "No URL"
}
} catch {
print("Error: \(error.localizedDescription)")
}
}
.resume()
}
Now, how can I display the image after the user presses on the Button?
I'm trying to get some data from a json Api and display this data along with an image. First I have a function that fetches the data from the Api, then I have another function that downloads the image data. The problem is that the second function doesn't seem to be working right and the image data is never recieved.
func fetchAPI() {
URLSession.shared.dataTask(with: url) { (data, response, error) in
		/* Code that decodes the json and gets the imageURL string */
DispatchQueue.main.async {
self.downloadImage(url: imageURL)
}
} catch {
print("Error: \(error.localizedDescription)")
}
}
.resume()
}
The function that downloads the image:
func downloadImage(url: String) {
print("Downloading Image...")
guard let imageURL = URL(string: url) else {
print("Error: Invalid image URL")
return
}
URLSession.shared.dataTask(with: imageURL) { data, response, error in
guard let recievedData = data, error == nil else {
print("Error: No Data")
return
}
print("Got Data") <- Doesn't output to console
												print(recievedData) <- Doesn't output to console
DispatchQueue.main.async {
self.imageData = recievedData <- Nothing
}
}
}