Angelo Stavrow [dot] Blog

swiftui

Using @EnvironmentObject is a great way to share data between your views. Previously, I'd been using @ObservedObjects all over my views, and it felt clumsy.

Hot tip: by setting an environmentObject for a NavigationView, any children of this NavigationView can then add a property like @EnvironmentObject var someType: SomeType. SwiftUI then gives them access to the observed object, without you having to pass the object down the navigation tree and through views that don't need access to it:

/* ContentView.swift */

import SwiftUI

struct ContentView: View {
    @ObservedObject var someType: SomeType

    var body: some View {
        NavigationView {
            MyView()
        }
        .environmentObject(someType)
    }
}

/* MyView.swift */

import SwiftUI

struct MyView: View {
    var body: some View {
        SomeTypeList()
    }
}


/* SomeTypeList.swift */

import SwiftUI

struct SomeTypeList: View {
    @EnvironmentObject var someType: SomeType
    
    var body: some View {
        // Do something with someType
    }
}

But! If you were passing it in to a child view as an ObservedObject and had set up some test object for use in your SwiftUI preview? If you try to pass in your test object, you'll get an error:

Cannot convert value of type 'SomeType' to expected argument type 'EnvironmentObject<SomeType>'

To fix this, use the environmentObject modifier on your child view's preview provider:

struct SomeTypeList_Previews: PreviewProvider {
    static var previews: some View {
        SomeTypeList()
            .environmentObject(testSomeType)
    }
}

Yay, your preview works again!

#swift #swiftui

Discuss...

Hot on the heels of the WriteFreely Swift Package, I'm kicking off another fun open-source project: building a WriteFreely client for all Apple platforms as a SwiftUI multiplatform app.

I've written about the project a bit more here, where I'm sharing updates on the WriteFreely/Write.as work I do. If WWDC got you interested in learning more about multiplatform apps and SwiftUI, join me in building this! The goal is to go from what you see in the GitHub project today to a functional app by the end of August. Developers of any level of experience are welcome!

This work will have two tracks — building the client app, which will be the bulk of the work, and improving the Swift package. Personally, I'm more excited about SwiftUI and multiplatform apps than I've been about other tech stacks in a long time.

That said, one of the reasons Per has been stagnating for as long as it did was because I got bitten by the Swift 2 → 3 transition, which kinda broke everything. I'm hoping that it'll be smoother for SwiftUI as it's improved and extended over the next few years.

More TK!

#writeas #projects #swift #swiftui

Discuss...

A little bit of a UI/UX deficiency I've found when using Swift Package Manager in Xcode 12 β2 is that adding a Swift package to a multiplatform (iOS/macOS) SwiftUI app requires you to choose a target for the package:

"Add Package to App sheet in Xcode showing a target selection menu"

That means that if you have a platform-agnostic package that you import, and try to use it for both the iOS and macOS targets, you'll invariably run across an error (”No such module 'ModuleName'”) when you're writing code against the target you didn't add it to in the above step, and your project won't build for that target.

To fix this, Stuart Breckenridge shared the following tip: go to the Build Phases tab for each of your targets, and make sure it's added under Link Binary with Libraries:

"Target Build Phases settings in Xcode"

Build the app, and you'll be good to go.

I've filed FB8094575 to improve this user flow.

#spm #swiftui #swift

Discuss...