iOS Development

ios – What’s the level of MVVM in Swift? It feels advanced and pointless. Most of my information comes from the server and I have to handle that throughout views

Spread the love


I promise, this isn’t a rant. I am actually attempting to wrap my head across the professionals and cons of MVVM. As I used to be constructing my software I used to be attempting to comply with MVVM as greatest as I may however there have been cases the place a view didn’t want want a devoted view mannequin because it required information that was in one other view already.

That is once I found Apples new Observable Macro and the way it works underneath the hood. I attempted to make use of it in a MVVM structure manner however did not see what the purpose was after watching some developer movies:

https://developer.apple.com/movies/play/wwdc2020/10040/
https://developer.apple.com/movies/play/wwdc2023/10149/

In these examples they spotlight inserting the Observable class into the Surroundings and utilizing it in little one views as wanted. Since Observable could be very clever underneath the hood it doesn’t trigger pointless rerenders.

So that is what I did. I created “Controllers” for a selected a part of my software and handed them into the surroundings on the applicable father or mother degree.

I do not even know what structure I am following, if any. However it works. It really works precisely how I count on an software ought to.

I created an AuthController that I handed into the surroundings on the root degree. This gave my touchdown display screen entry to the log in operate and my settings display screen entry to the log off.

closing class AuthController {
    
    func signInWithApple(utilizing idToken: String) async -> () {
        do {
            let credentials = OpenIDConnectCredentials(supplier: .apple, idToken: idToken)
            attempt await supabaseClient.auth.signInWithIdToken(credentials: credentials)
        } catch {
            print(error)
        }
    }
    
    func signOut() async -> () {
        do {
            attempt await supabaseClient.auth.signOut()
        } catch {
            print("error", error)
        }
    }
}

One other instance of a controller I created was the UserController. To deal with updating the customers information (profile) and updating the UI wherever it might be used.

@Observable closing class UserController {
    
    non-public(set) var userProfile: UserProfile?
    
    func getUserProfile() async -> () {
        do {
            let person = attempt await supabaseClient.auth.session.person
            let userProfile: UserProfile = attempt await supabaseClient.database
                .rpc("get_user_profile", params: [ "user_id" : user.id.uuidString ])
                .choose()
                .execute()
                .worth
            
            self.userProfile = userProfile
        } catch {
            print("error", error)
        }
    }
    
    func updateUsername(newUsername: String) -> () {
        userProfile?.updateUsername(newUsername: newUsername)
    }
    
}

I injected this into the surroundings on the TabView degree so all the applying screens have entry to the person information and may replace them when wanted. A fast take a look at of updating the username from two completely different tab views works as anticipated.

struct HomeView: View {
    
    @Surroundings(UserController.self) var userController
    
    var physique: some View {
        ScrollView {
            VStack {
                if let userProfile = userController.userProfile {
                    Textual content("(userProfile.username)")
                }
                
                Button("Get information") {
                    Job {
                        await userController.getUserProfile()
                    }
                }
                
                Button("Replace username") {
                    userController.updateUsername(newUsername: "HomeViewUsername")
                }
            }
        }
    }
}

struct ProfileView: View {
    
    @Surroundings(UserController.self) var userController
    
    var physique: some View {
        ScrollView {
            VStack {
                if let userProfile = userController.userProfile {
                    Textual content("(userProfile.username)")
                }
                
                Button("Replace username") {
                    userController.updateUsername(newUsername: "ProfileViewUsername")
                }
            }
        }
    }
}

Is there one thing apparent I am lacking? It does really feel that I’m lacking one thing and I welcome any suggestions so I can study.

Leave a Reply

Your email address will not be published. Required fields are marked *