Giter Site home page Giter Site logo

tgrapperon / swift-dependencies-additions Goto Github PK

View Code? Open in Web Editor NEW
278.0 278.0 31.0 574 KB

More dependencies for `swift-dependencies`

License: MIT License

Swift 99.56% Makefile 0.44%
apple-framework architecture dependencies dependency-injection swift testing

swift-dependencies-additions's People

Contributors

acosmicflamingo avatar atacan avatar finestructure avatar jacksonutsch avatar john-flanagan avatar myihsan avatar sajjon avatar siemensikkema avatar tgrapperon 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swift-dependencies-additions's Issues

Additions suggestion/request

Hi Thomas,

I'd like to suggest two additions to your dependencies library:

  • a way to set the user interface style (ie, dark or light mode)
  • a way to directly get and set dates in UserDefaults

Thanks!

Improve `Logger`'s behavior when testing.

Right now, the Logger dependency has a subscript that allows to post logs to a specific category on the spot:

@Dependency(\.logger["MyCategory"]) var logger

Sending messages to this logger will log them under the "MyCategory" category of the subsystem represented by you app's bundle identifier. In other words, it is equivalent to post on:

Logger(subsystem: "com.mycompany.myapp", category: "MyCategory")

This is the default Apple is suggesting in the documentation.

For consistency, the library uses its Bundle dependency to fill this information. But this has the annoying side effect of forcing users to explicitly specify a bundle identifier when testing. The bundle identifier dependency indeeds defaults to unimplemented when testing.

This is highly unintuitive. I'm exploring alternative solutions/workarounds, and also if there is something more general around the ergonomics of dependencies that embed other dependencies.

Add ergonomic location dependency

After we add support for CLLocationManager, I would like to add a more ergonomic wrapper around it, allowing things like getLocation() async throws -> CLLocationCoordinate2D.

With CLLocationManager working with a delegate pattern, it's a bit complex to implement correctly but I did it in a simple project so I should be able to replicate it here.

I'm just not sure what features we would like to add in this dependency. Thinking about it for 1 minute, I see something like:

  • getLocation() async throws -> CLLocationCoordinate2D
  • locations() -> AsyncStream<CLLocationCoordinate2D>

`_CoreDataDependency` doesn't update its `Fetched` item.

Discussed in #67

Originally posted by m-housh May 19, 2023
Forgive my ignorance with CoreData in general, but I'm playing around with the _CoreDataDependency and trying to determine how to update a Fetched item. I have tried several approaches, mainly the following...

struct TodoFeature: Reducer {
  struct State: Equatable {
     var todos: Todo.FetchedResults = .empty
  }

  Action: Equatable {
    ...
    case toggleComplete(todo: Fetched<Todo>)
  }

  @Dependency(\.persistentContainer) var persistentContainer;

  var body: some ReducerOf<Self> {
    Reduce { state, action in
      switch action {
       ...
       case .toggleComplete(todo: let todo):
          todo.withManagedObject { update in 
            update.complete.toggle()
            try! update.managedObjectContext!.save()
          }
         return .none
      }
      
    }
  }
}

This does not update the view / state, however if I shut the app down and restart it, the complete value is toggled. So I'm not sure if I need to invalidate the cached items that have been fetched, but calling my task that initially loads the todo's does not seem to update the todo's state either. Once again, forgive my ignorance in working with core data in general as it seems like there's something basic that I'm missing.

Here's the repository for more complete example.

https://github.com/m-housh/CoreData_Test

@Dependency.AppStorage does not work when used with SwiftUI picker

Hi,

I have a SwiftUI Form which shows a Picker which is driven by a @Dependency.AppStorage backed property in my model. The corresponding user default is set when changing the picker's selection, but the view is not updated accordingly. The picker is not dismissed and the checkmark does not change.

class ViewModel: ObservableObject {
    @Dependency.AppStorage("myDefault") public var myDefault = "one"
}

struct MyView: View {
    @StateObject var viewModel = ViewModel()

    var body: some View {
        NavigationStack {
            Form {
                Picker("Default value", selection: $viewModel.myDefault) {
                    Text("one").tag("one")
                    Text("two").tag("two")
                    Text("three").tag("three")
                }
            }
        }
    }
}

Any ideas?

Btw: I'm using watchOS.

TCA 1.2.0 compatibility

I am using Tuist to build the project and using latest TCA v1.2.0. But when I fetch the dependencies I am getting the error:
Dependencies could not be resolved because root depends on 'swift-dependencies-additions' 0.1.0..<1.0.0 and root depends on 'swift-composable-architecture' 1.2.0..<2.0.0. when trying to link the package.

error: Dependencies could not be resolved because root depends on 'swift-dependencies-additions' 0.1.0..<1.0.0 and root depends on 'swift-composable-architecture' 1.2.0..<2.0.0.
'swift-dependencies-additions' is incompatible with 'swift-composable-architecture' because 'swift-composable-architecture' 1.2.0 depends on 'xctest-dynamic-overlay' 1.0.0..<2.0.0 and no versions of 'swift-composable-architecture' match the requirement 1.2.1..<2.0.0.
If 'swift-dependencies-additions' 0.1.0..<1.0.0 and 'swift-composable-architecture' 1.2.0 then 'xctest-dynamic-overlay' 0.8.0..<1.0.0 because 'swift-dependencies-additions' 0.5.2 depends on 'xctest-dynamic-overlay' 0.8.0..<1.0.0 and 'swift-composable-architecture' 1.2.0 depends on 'swift-dependencies' 1.0.0..<2.0.0.
'swift-dependencies-additions' {0.1.0..<0.5.2, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 or 'xctest-dynamic-overlay' 0.8.0..<1.0.0 because 'swift-dependencies-additions' 0.5.0 depends on 'swift-dependencies' 0.4.0..<1.0.0 and 'swift-dependencies-additions' 0.5.1 depends on 'xctest-dynamic-overlay' 0.8.0..<1.0.0.
'swift-dependencies-additions' {0.1.0..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because 'swift-dependencies-additions' 0.3.2 depends on 'swift-dependencies' 0.1.0..<1.0.0 and 'swift-dependencies-additions' 0.4.0 depends on 'swift-dependencies' 0.1.0..<1.0.0.
'swift-dependencies-additions' {0.1.0..<0.3.2, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because 'swift-dependencies-additions' 0.3.0 depends on 'swift-dependencies' 0.1.0..<1.0.0 and 'swift-dependencies-additions' 0.3.1 depends on 'swift-dependencies' 0.1.0..<1.0.0.
'swift-dependencies-additions' {0.1.0..<0.3.0, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because 'swift-dependencies-additions' 0.1.3 depends on 'swift-dependencies' 0.1.0..<1.0.0 and 'swift-dependencies-additions' 0.2.0 depends on 'swift-dependencies' 0.1.0..<1.0.0.
'swift-dependencies-additions' {0.1.0..<0.1.3, 0.1.4..<0.2.0, 0.2.1..<0.3.0, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because 'swift-dependencies-additions' 0.1.1 depends on 'swift-dependencies' 0.1.0..<1.0.0 and 'swift-dependencies-additions' 0.1.2 depends on 'swift-dependencies' 0.1.0..<1.0.0.
'swift-dependencies-additions' {0.1.0..<0.1.1, 0.1.4..<0.2.0, 0.2.1..<0.3.0, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because 'swift-dependencies-additions' 0.1.0 depends on 'swift-dependencies' 0.1.0..<1.0.0.
'swift-dependencies-additions' {0.1.0, 0.1.4..<0.2.0, 0.2.1..<0.3.0, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} practically depends on 'swift-dependencies' 0.1.0..<1.0.0 because no versions of 'swift-dependencies-additions' match the requirement {0.1.4..<0.2.0, 0.2.1..<0.3.0, 0.3.3..<0.4.0, 0.4.1..<0.5.0, 0.5.3..<1.0.0} and 'swift-dependencies-additions' 0.1.0 depends on 'swift-dependencies' 0.1.0..<1.0.0.

Any help would be appreciated

Current state of documentation?

At first I thought there was no documentation for this repo since it's not mentioned in the ReadMe. I see that there used to be documentation on github pages, but that looks inactive now. I did see that swift package index is hosting documentation here, however, it looks like it's missing everything except for the front page.

Finally, I built the documentation for myself in Xcode and discovered that there's already fantastic documentation. You can find it be using Product > Build Documentation then Window > Developer Documentation, or you can also use Xcode 15's new Documentation Preview Assistant.

To help with discoverability, could we please add a link to the documentation in the ReadMe.
Also, could we reach out to swift package index to find out why their documentation hosting is missing pages?

If you want you can assign this to me.

`UserDefaults.Dependency.previewValue` leaks to other `withDependencies`'s?

Hello, I've found out that UserDefaults.Dependency.previewValue does not re-initialize and leaks to other withDependencies's.

Here is a MWE. With the following view / model pair,

final class ContentViewModel: ObservableObject {
    @Published var text1 = "nil"
    @Published var text2 = "nil"
    @Dependency.AppStorage("myDefault1") private var myDefault1: String?
    @Dependency.AppStorage("myDefault2") private var myDefault2: String?
    init() {
        if let myDefault1 { text1 = myDefault1 }
        if let myDefault2 { text2 = myDefault2 }
    }
}
struct ContentView: View {
    @ObservedObject private(set) var viewModel: ContentViewModel
    var body: some View {
        VStack {
            Text(viewModel.text1)
            Text(viewModel.text2)
        }
    }
}

when I setup a preview as:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(viewModel: withDependencies {
//            $0.userDefaults = .previewValue
            $0.userDefaults.set("v1", forKey: "myDefault1")
        } operation: {
            ContentViewModel()
        })
        ContentView(viewModel: withDependencies {
//            $0.userDefaults = .previewValue
            $0.userDefaults.set("v2", forKey: "myDefault2")
        } operation: {
            ContentViewModel()
        })
    }
}

the two ContentViews display the same content, which means that the .previewValue is not being reset. Removing either of the comments work as (I have) expected.

I'm not 100% sure if this is a bug, but it seems misleading because the documentation for withDependencies says (emphasis mine):

updateValuesForOperation A closure for updating the current dependency values for the duration of the operation.

I initially discovered this behavior testing a somewhat complex logic---involving asynchronous codes manipulating user default key-value pairs---, and it took quite a bit of time to locate the cause.

Should this be considered a bug, or an expected behavior?
Thanks!

Lightweight persistence on disk (alternative to the beast that is CoreData) dependency?

Hey Thomas! Any plans on adding a lightweight persistence dependency that saves data (Codables) to the file system? Potentially just a wrapper around some other library? I've used Disk in the past, but it seems dead, and is iOS only (was gonna fix that, but saw PRs seem to be ignored, because not maintained). So I took a look around and potentially these are candidates more suitable than Disk?

Or are you reluctant adding a SPM dependency to implement a... dependency ๐Ÿคช, I completely understand that if that is the case. If so, any plans for implementing this yourself?

userDefaults: Unimplemented error in case with provided dependency value

I'm not sure if it's a bug or I'm doing something wrong, but there is an equal chance to get the test passed or failed using this code:

final class ViewSpec: QuickSpec {
  // MARK: Spec

  override func spec() {
    describe("View") {
      let width = 320.0

      let height = 1000.0
      it("should match snapshots in dark mode") { @MainActor in
        withDependencies {
          $0.userDefaults = .liveValue
        } operation: {
          assertSnapshot(
            matching: View(screenWidth: width, previousView: String())
              .environment(\.colorScheme, .dark),
            as: .image(layout: .fixed(width: width, height: height)),
            named: "View.dark"
          )
        }
      }
      it("should match snapshots in light mode") { @MainActor in
        withDependencies {
          $0.userDefaults = .liveValue
        } operation: {
          assertSnapshot(
            matching: View(screenWidth: width, previousView: String())
              .environment(\.colorScheme, .light),
            as: .image(layout: .fixed(width: width, height: height)),
            named: "View.light"
          )
        }
      }
    }
  }
}

It always passes in dark mode but has a random chance of failing in light mode. ๐Ÿค”
Uncaught Exception: Unimplemented: @Dependency(\.userDefaults)

Overriding dependencies on @FunctionProxy's fail when they accept a parameter

I don't understand the cause of this but when I put this in my test, it refuses to build:

await withDependencies {
            $0.userNotificationCenter.$add = { @Sendable userNotificationRequest in
                await requests.setValue([userNotificationRequest])
            }
        } operation: {
           // ...
        }

Xcode provides no error other than Command SwiftCompile failed with a nonzero exit code. (I did also clean my build folder and clear derived data folder). After much sleuthing I found that the offending line was this:

           $0.userNotificationCenter.$add = { @Sendable userNotificationRequest in
                await requests.setValue([userNotificationRequest])
            }

When I remove it, the test builds. When I assign it as a variable rather than inline, then it builds.

let add = { @Sendable userNotificationRequest in
                await requests.setValue([userNotificationRequest])
            }
            $0.userNotificationCenter.$add = add // this builds

Is this a bug, or am I using something wrong?

You can see the full code at: https://github.com/DandyLyons/BrittanyArima-Steps/blob/31-add-unit-tests/StepsTests/SettingsViewTests.swift

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.