Coder Social home page Coder Social logo

lickability / observableconverter Goto Github PK

View Code? Open in Web Editor NEW
87.0 3.0 1.0 53 KB

A SwiftPM command plugin to convert SwiftUI code to Observable

Home Page: https://lickability.com/blog/introducing-observableconverter/

License: MIT License

Swift 100.00%
command-plugin swift swiftpm swiftui tooling xcode ios ios-swift swift-package swift-packages

observableconverter's Introduction

ObservableConverter

ObservableConverter from Lickability is a basic plugin to help convert your SwiftUI code using ObservableObject and related property wrappers and view modifiers to instead use Apple's new @Observable macro, introduced at WWDC 2023 in iOS 17, macOS 14, watchOS 10, and tvOS 17.

A screenshot of the menu you see when right-clicking a target, with the ObservableConverter plugin option highlighted

Installation

ObservableConverter is a Swift Package Manager command plugin, so installation is only available through SPM on Xcode 15 beta 7 and later.

In Xcode, go to File and select Add Package Dependencies. Paste the URL of this repo into the search bar and select it. When it asks what framework to embed in your target, select None, as this tool is purely for code conversion purposes and should not be built as part of your app.

Usage

As a command plugin, once ObservableConverter is installed it's as simple to use as right clicking on the target you want to convert in the Xcode project navigator and choosing the Convert Target to Use @Observable option in the menu!

This repo also includes an example project using ObservableObject so you can see the conversion yourself. Open up the xcodeproj in the Examples folder and right click on the target to see it convert the existing code to use @Observable!

Here's what some of the example code looks like before the conversion:

final class ViewModelTest: ObservableObject {
    @Published var publishedProperty: String?
}

struct ContentView: View {
    @StateObject private var viewModel = ViewModelTest()
    @EnvironmentObject private var environmentModel: ViewModelTest
    
    var body: some View {
        VStack {
            ChildView(model: viewModel)
                .environmentObject(environmentModel)
        }
        .padding()
    }
}

struct ChildView: View {
    @ObservedObject var model: ViewModelTest
    
    var body: some View {
        Text(model.publishedProperty ?? "no value set")
            .onTapGesture {
                model.publishedProperty = "model value changed"
            }
    }
}

And here's after ๐ŸŽ‰:

@Observable
final class ViewModelTest {
    var publishedProperty: String?
}

struct ContentView: View {
    @State private var viewModel = ViewModelTest()
    @Environment(ViewModelTest.self) private var environmentModel 
    
    var body: some View {
        VStack {
            ChildView(model: viewModel)
                .environment(environmentModel)
        }
        .padding()
    }
}

struct ChildView: View {
    var model: ViewModelTest
    
    var body: some View {
        Text(model.publishedProperty ?? "no value set")
            .onTapGesture {
                model.publishedProperty = "model value changed"
            }
    }
}

Notes

While this tool handles basic conversion instances, it is still very much in beta and will need some additional functionality. Please use under source control so that you can revert any changes that you don't like.

More advanced use cases that could be handled in the future:

  • Optionally converting lazy properties to @ObservationIgnored
  • Converting onReceive usage for converted @Published properties.
  • Better handling of Combine within ObservableObject classes, such as converting the assign(to published:) operator and handling @Published property observation.
  • Scanning for binding use cases of @EnvironmentObject and applying @Bindable in line when necessary.

Need More Help?

Need more help getting your app ready for iOS 17+? That's what we do at Lickability โ€“ reach out to see how we can be of service!

Lickability

observableconverter's People

Contributors

bcapps avatar samhenrigold avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

mastermikk

observableconverter's Issues

Handle Combine Usage within `ObservableObject`

Feature Proposal

Handle Combine usage such as assign(to published:) and internal @Published property observation.

Acceptance Criteria

  • The conversion should convert to assign(to:) to another supported call, and should handle fallbacks for @Published property observation such as either keeping those @published or adding CurrentValueSubject properties that are updated on didSet instead.

Apply @Bindable Where Necessary

Feature Proposal

When referencing EnvironmentObject or @ObservedObject properties as bindings, we should make use of @Bindable or the Bindable initializer to prevent a build error.

Acceptance Criteria

  • Binding references to environment objects should no longer trigger errors after conversion

Convert `onReceive` Usage for `@Published` Properties on `ObservableObject`

Feature Proposal

Convert onReceive references in SwiftUI views to use another view modifier instead now that properties will no longer be publishers. Something like onChange could work instead.

Acceptance Criteria

  • Any onReceive that references a formerly @Published property on an ObservableObject should now be a different view modifier that preserves the same functionality

Optionally Add `@ObservationIgnored` to `ObservableObject` Lazy Properties

Feature Proposal

Add a flag to the command to mark any lazy property in an ObservableObject as @ObservationIgnored, as otherwise lazy properties will cause build errors now. Decide whether it should be enabled or disabled by default.

Acceptance Criteria

  • A flag for this exists on ObservableConverterCommand and can be sent to Arguments when running
  • The flag does the conversion to mark every lazy property in an ObservableObject as @ObservationIgnored

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.