I am trying to convert my Swift App into SwiftUI. In My Swift App I am having one listener class inheriting in home class. In that home class one function is calling. (Home is Viewcontroller class)
I am trying to do same in SwiftUI but as SwiftUI View is struct can't do that.
Sharing my Swift Code
extension Home: Listener {
func event(_ event: Event) {
if event == HomeEvent.check{
if let response = event as? CheckG {
handleCheck(response)
}
}
}
public protocol Listener: class {
func event(_ event: Event)
}
In SwiftUI
struct Home: View {
var body: some View {
VStack() {
Text("Home")
}
}
My question might be wrong as I am new to iOS ..Request you to guide on my query.
Thank You for help
Related
I know that this may be tagged as a repeat question, but the ones that exist have not helped me implement delegates in Swift with SwiftUI. My issue can be see in the code below. I have a View and VM, TodaysVM. In here, I do a network request, that downloads movie data from an API, and saves the data to CoreData. In order to show graphs, the HabitVM needs to fetch the data from CoreData, and then do some long processing on it.
For this, I was looking into a way for one class to send a message notification to another class. So I stumbled onto using delegates (not sure if this is correct?). But essentially the idea would be that the TodayVM refreshes its data (which the user can do a pull to refresh on this page), it also sends a message to HabitsVM to start processing (so the data can be done by the time the user navigates to this page. I am not sure if there is a better way to do this, and I was trying to stay away from a singleton approach, passing one class into class, or creating a new instance of one of the classes.
In the code below, I have the delegates set up but 'print("Data update required!")' is never executed. From my research I understand this to be because I never set a value to the delegate? So the delegate value is nil, and therefore the
delegate?.requireUpdate(status: true)
Is never actually executed. Which makes sense, since delegate is an optional, but never assigned a value. So I was curious how I would assign it a value in SwiftUI? And if using delegates is even the best method to have to separate classes send updateRequired status updates.
import SwiftUI
import Foundation
// protocol
protocol MovieNotifierDelagate: AnyObject {
func requireUpdate(status: Bool)
}
struct HabitView {
#StateObject var habitVM = HabitsVM()
var body: some View {
Text("Hello")
}
}
struct TodaysView {
#StateObject var todayVM = TodayVM()
var body: some View {
Text("Hi!")
}
}
class HabitsVM: ObservableObject, MovieNotifierDelagate {
init() {
}
func requireUpdate(status: Bool) {
print("Data update required!")
reprocessData()
}
func reprocessData() {
print("Processing")
}
}
class TodayVM: ObservableObject {
weak var delegate: MovieNotifierDelagate?
init() {
//Does some network call and downloads data, and saves to CoreData
sendUpdate(status: true)
}
func sendUpdate(status: Bool) {
guard status else {
print ("No update")
return
}
delegate?.requireUpdate(status: true)
}
}
// Controlling Page
struct HomeView: View {
//Default the user to the today view
#State private var selection = 1
var body: some View {
TabView(selection: $selection) {
HabitView()
.tag(0)
.tabItem {
VStack {
Image(systemName: "books.vertical")
Text("Habits")
}
}
TodaysView()
.tag(1)
.tabItem {
VStack {
Image(systemName: "backward.end.alt")
Text("Rewind")
}
}
}
}
}
I am trying to build a SwiftUI tvOS app.
As you can see here, I am trying to create a SwiftUI View using a UIViewControllerRepresentable, specifically for the DDDevicePickerViewController.
However, I noticed that there is no DDDevicePickerViewControllerDelegate while I was trying to implement it, which is needed according to Paul Hudson's tutorial. How can I use the DevicePickerView in SwiftUI?
I tried to use this code to create it, so when I use it, I just get a black screen with no errors in the logs:
import Foundation
import SwiftUI
import DeviceDiscoveryUI
public struct DDevicePickerView: UIViewControllerRepresentable {
let viewController: DDDevicePickerViewController
public init() {
// Create the view controller for the device picker.
let devicePicker = DDDevicePickerViewController(browseDescriptor: .applicationService(name: "TicTacToe"),
parameters: applicationServiceParameters())
self.viewController = devicePicker!
}
public func makeUIViewController(context: Context) -> DDDevicePickerViewController {
let gkVC = viewController
return gkVC
}
public func updateUIViewController(_ uiViewController: DDDevicePickerViewController, context: Context) {
return
}
}
SwiftUI already has a wrapper DevicePicker
But if you want to wrap it yourself, start with something like this and then you just have to figure out how to get the async endpoint result. It is quite unusual to have view controllers be async like this.
import Foundation
import SwiftUI
import DeviceDiscoveryUI
public struct DevicePicker: UIViewControllerRepresentable {
#Binding var isPresented: Bool
public func makeUIViewController(context: Context) -> UIViewController {
UIViewController()
}
public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
if isPresented {
if uiViewController.presentedViewController != nil {
return
}
let = picker DDDevicePickerViewController(browseDescriptor: .applicationService(name: "TicTacToe"), parameters: applicationServiceParameters())
uiViewController.present(picker, animated: !context.transaction.disablesAnimations)
}
else {
uiViewController.presentedViewController?.dismiss()
}
}
}
I have a state String variable called fullLogMessages
In my ViewController I set the fullLogMessage through given callbacks. This fulllogMessage I then get from a LogViewModel I created
I can get it to update a TextField on a button click to add a request has been sent, but unsure how to update the Textfield for the subsequent callbacks.
SwiftUI
import SwiftUI
struct TestAdsView: View {
#StateObject var lvm: LogsViewModel = LogsViewModel()
var body: some View {
VStack{
Text(vm.adStatus.rawValue)
TextField("Logs", text: $lvm.getFullLogMessage)
Button("load Ads", action: {
vm.loadAds()
})
AdsScreenView_UI(viewModel: vm).frame(width: 0, height: 0)
}
}
}
struct AdsScreenView_UI: UIViewControllerRepresentable{
#ObservedObject var viewModel: AdsScreenViewModel
func makeUIViewController(context: Context) -> some AdsScreenViewController {
print(#function)
return AdsScreenViewController(viewModel: viewModel)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
print(#function)
}
}
I'm a bit stuck on how I can get the TextField to update from getting the message in the updateUIViewController. This method gets called after each callback but no idea how to update the view with the given message.
Previously in WatchKit we could tell a certain InterfaceController to present itself using .becomeCurrentPage, how can we do it in Swift UI?
In WatchKit for example I would:
// handle notification
#objc func respondToWaterlock(_ notification: NSNotification) {
self.becomeCurrentPage()
}
there is no equivalent for becomeCurrentPage method in SwiftUI. You can update your State or ViewModel to achieve a similar result.
for example:
enum Pages {
case home
case settings
}
struct MyView: View {
#State var selectedPage: Pages = .home
var body: some View {
Group {
if self.selectedPage == .home {
Text("Home")
} else if self.selectedPage == .settings {
Text("Settings")
}
}
}
}
You should just update the selectedPage state variable to change the page.
I am a newbie in IOS Programming and also SwiftUI. Coming from Java/Kotlin Android. I want to learn SwiftUI.
I have a WKWebView. I want to change SwiftUI page according to url changes in WKWebView. I have done a lot of work as you can see below. But I am struggled in navigation.
struct ContentView: View, Listener {
func onFetched() {
NavigationLink(destination: MainView()) {/* HERE this is not working.
App never goes to MainView.swift page.*/
Text("Show Detail View")
}
}
var body: some View {
NavigationView {
VStack {
WebView(authListener: self)
}.navigationBarTitle(Text("PEAKUP Velocity"))
}
}
}
struct WebView: UIViewRepresentable {
var listener: Listener
#ObservedObject var observe = observable()
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
observe.observation = uiView.observe(\WKWebView.url, options: .new) { view, change in
if let url = view.url {
self.observe.loggedIn = true // We loaded the page
self.listener.onFetched()
uiView.isHidden = true
}
}
uiView.load("https://google.com")
}
}
protocol Listener {
func onFetched()
}
Update: I tried this in onFetched():
NavigationLink(destination: MainView()) { Text("") }''''
And I tried this piece of code:
NavigationView {
NavigationLink(destination: SecondView()){
Text("Navigation Link")
}
}
Update 2: I tried this code also in onFetched:
self.presentation(Model(MainView(), onDismiss: nil))
Update 3: I tried this:
self.sheet(isPresented: $sayHello) {
MainView()
}
** Disclaimer I haven't used WKWebviews in the context of SwiftUI, but I assume same would be true. **
I would recommend looking into WKNavigationDelegate. Unless your class is of type WKWebView you need to ensure to assign a delegate to handle any navigation events.
Perhaps you'll find the below article helpful: https://www.hackingwithswift.com/articles/112/the-ultimate-guide-to-wkwebview