Git Product home page Git Product logo

dikit's People

Contributors

ikesyo avatar ishkawa avatar mshibanami avatar nakiwo avatar takasek avatar yutailang0119 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

dikit's Issues

Property version of Injectable

When we use storyboard segue. We don't instantiate view controller, but we receives a new view controller immediately after instantiation by storyboard segue.In this case, we can't use Injectable and FactoryMethodInjectable (explained in #2).

One possible way to inject dependency is property injection.

protocol PropertyInjectable {
    associatedtype Dependency
    var dependency: Dependency! { get set }
}

Once a type conforms to PropertyInjectable, it should be able to receive dependencies via inject(toSomeClass:) method.

// Generated code by dikitgen
extension SomeResolver {
    func inject(toSomeClass: SomeClass) {
        someClass.dependency = ...
    }
}

About Output Files in Xcode10 or later

Hi, @ishkawa

I'm using your library in product and CI. I noticed that it always fails building in CI.

To use this library in Xcode 10 (or above) and CI, I use output files like "$SRCROOT/AppResolver.generated.swift" in Run Script phases, which also done in R.swift.

Please add about "Output Files" to README.

Thanks!

Add Shared<T> to return shared instance in provider method

Rough sketch:

final class Counter {
    var value = 0
}

protocol MyResolver: Resolver {
    // A MyResolver instance always returns the same instance of Counter. 
    func provideCounter() -> Shared<Counter>
}

// Generated code
extension MyResolver {
    func resolveCounter() -> Counter {
        final class Scope {
            // NOTE: WeakDictionary doesn't present in standard library.
            static var sharedInstances = [:] as WeakDictionary<MyResolver, Counter>
        }

        // Return shared instance associated with MyResolver instance if it presents.
        if let sharedInstance = Scope.sharedInstances[self] {
            return associatedObject
        }

        // If shared instance is not found, call provider method and save returned instance as a shared instance.
        let sharedInstance = provideCounter()
        Scope.sharedInstances[self] = sharedInstance
        return sharedInstance
    }
}

What is the vision for the project?

I am super interested in this project and recently started working on a similar concept but I think it would be best to help contribute to this project instead. What are the goals and milestones for the future of this project so that I can help contribute and place efforts where they are most needed?

Introduce errors to dikitgen

At this moment, dikitgen never reports errors.
Errors are useful for developers to find out what is wrong and how can they fix them.

Convert dependency type from struct to tuple

Currently, dikitgen expects that Injectable.Dependency is declared as a struct.

Structs can have computed properties and methods, but the type elements are not related to declaring dependencies. I think Injectable.Dependencyshould focus on expressing dependencies, and the other works should be done by other components.

To encourage developers to focus on defining dependencies, I'm planning to convert Injectable.Dependency to tuple type.

Can not generate multiple "Resolver" correctly.

Expected behavior

I wrote this test in forked project. (Tests/DIGenKitTests/CodeGeneratorTests.swift)
But failed.

func testMultipleResolver() throws {
        let code = """
            import DIKit

            struct A: Injectable, FactoryMethodInjectable {
                struct Dependency {
                    let value: Int
                }

                init(dependency: Dependency) {}

                static func makeInstance(dependency: Dependency) {}
            }

            struct B: Injectable, FactoryMethodInjectable {
                struct Dependency {
                    let value: Int
                }

                init(dependency: Dependency) {}

                static func makeInstance(dependency: Dependency) {}
            }

            protocol TestResolverA: Resolver {
                func provideA() -> A
            }

            protocol TestResolverB: Resolver {
                func provideB() -> B
            }
            """
        
        let file = File(contents: code)
        let generator = try CodeGenerator(files: [file])
        let contents = try generator.generate().trimmingCharacters(in: .whitespacesAndNewlines)
        
        // Generated code uses provider method only
        XCTAssertEqual(contents, """
        //
        //  Resolver.swift
        //  Generated by dikitgen.
        //

        import DIKit

        extension TestResolverA {

            func resolveA() -> A {
                return provideA()
            }

        }

        extension TestResolverB {

            func resolveB() -> B {
                return provideB()
            }

        }
        """)
    }

Actual Behavior

//
// Resolver.swift
// Generated by dikitgen.
//

import DIKit

extension TestResolverA {

    func resolveA() -> A {
        return provideA()
    }

    func resolveB(value: Int) -> B {
        return B(dependency: .init(value: value))
    }

}

extension TestResolverB {

    func resolveA(value: Int) -> A {
        return A(dependency: .init(value: value))
    }

    func resolveB() -> B {
        return provideB()
    }

}	

Factory method version of Injectable

There're some situations that developers can't override initializer. In such situations, factory method version of Injectable protocol helps developer to implement dependency injection.

Suppose we have UIViewController as a root view controller of storyboard. We can't make the view controller to conform Injectable, because we can't substitute storyboard view controller into self in init(dependency:).

To support this case, factory method version of Injectable is necessary.

protocol FactoryMethodInjectable {
    associatedtype Dependency
    static func makeInstance(dependency: Dependency) -> Self
}

Implementation of conformance looks like below:

final class SomeViewController: UIViewController, FactoryMethodInjectable {
    struct Dependency {...}

    static func makeInstance(dependency: Dependency) -> SomeViewController {
        let storyboard = UIStoryboard(name: "Some", bundle: nil)
        let viewController = storyboard.instantiateInitialViewController() as! SomeViewController
        viewController.dependency = dependency
        return viewController
    }

    private var dependency: Dependency!
}

Once SomeViewController conforms to FactoryMethodInjectable, it should be able to resolved same as conformers of Injectable.

// Generated code by dikitgen
extension SomeResolver {
    func resolveSomeViewController() -> SomeViewController {
        ...
        return makeInstance(dependency: ...)
    }
}

The xcodeproj is changed every time generate with Xcode 10.

I'm trying to support Xcode 10.
However, the generated xcodeproj is changed every time when I execute swift package generate-xcodeproj .

Swift Package Manager is not yet suitable for iOS.
I think that it is necessary to replace the generate of xcodeproj file with another tool.
I would like to consider migration from Swift Package Manager.

Ignore `Carthage/Checkouts/DIKit`

When separating sources to some frameworks, there are multiple directories on project root.
But if we use dikitgen for the project root, it recognizes Carthage/Checkouts/DIKit...

I find several ways to solve this issue,

  • static code to ignore Carthage directory.
  • white listing by letting dikitgen accept multiple arguments.
  • black listing
    • by command parameter which tells ignored directories
    • by introducing something such as .digenkitignore

The last one seems smart for me. Any idea?

Can not install applications on the actual iOS machine

Environment

  • DIKit 0.3.2
  • Xcode 9.3.1
    • Swift 4.1

Current behavior

There is no problem with the simulator, but applications depend on DIKit can not be installed on the actual iOS machine.

-[MIExecutableBundle codeSigningInfoByValidatingResources:performingOnlineAuthorization:ignoringCachedSigningInfo:checkingTrustCacheIfApplicable:error:]: 759: Code signing identifier (DIKit-5555494433789024584e33efa5e65138640f2c13) does not match bundle identifier (DIKit) for /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.boLOcV/extracted/Xxx.app/Frameworks/DIKit.framework

Xcode Alert image

Why

I think that this problem is caused by Swift 4.1 and SwiftPM.

Add PRODUCT_BUNDLE_IDENTIFIER = DIKit; to DIKit.xcodeproj/project.pbxproj after bfe0dc0.

This should be org.ishkawa.DIKit instead of DIKit.
And this causes unexpected behavior to DIKit_Info.plist.

Example via Carthage

/Carthage/Build/iOS/DIKit.framework/Info.plist infoplist

Expected Behavior

Unfortunately, I have no idea with a way to easily solve it.
However, I confirmed that it can be avoided by revert bfe0dc0.
yutailang0119@5dabb48

I'm investigating with @niwatako and @ikesyo

Documentation

  • Refined overview of library
  • Step by step instructions to integrate to Xcode project
  • 3 ways to provide dependency, injectable types, provider methods and parameters.

Question about using closure type constants in Dependency

When I define a class that conforms to Injectable and has a closure in its Dependency like below:

class SomeModel: Injectable {
    struct Dependency {
        let stringFactory: (Int) -> String
    }

    let stringFactory: (Int) -> String

    required init(dependency: Dependency) {
        self.stringFactory = dependency.stringFactory
    }
}

Then, I run dikitgen and I get error below. Closures in function parameter need @escaping.

    // Passing non-escaping parameter 'stringFactory' to function expecting an @escaping closure
    // Parameter 'stringFactory' is implicitly non-escaping
    func resolveSomeModel(stringFactory: (Int) -> String) -> SomeModel {
        return SomeModel(dependency: .init(stringFactory: stringFactory))
    }

I can avoid this error by creating factory container like below:

struct StringFactoryContainer {
    let factory:  (Int) -> String
}

And use like this:

class SomeModel: Injectable {
    struct Dependency {
        let stringFactoryContainer: StringFactoryContainer
    }

    let stringFactory: (Int) -> String

    required init(dependency: Dependency) {
        self.stringFactory = dependency.stringFactoryContainer.factory
    }
}

Does anyone know good way to use closure in Dependency?

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.