krzyzanowskim / Natalie

Natalie - Storyboard Code Generator (for Swift)
http://blog.krzyzanowskim.com/2015/04/15/natalie-storyboard-code-generator/
MIT License
1.17k stars 74 forks source link

Cannot declare a public var in an extension with internal requirements #124

Open aspyre opened 6 years ago

aspyre commented 6 years ago

I am getting a build issue in my generated output file. The issue is with this code:

extension IdentifiableProtocol where Self: ExpenseClaimsNavigationController {
    public var storyboardIdentifier: String? { return "ExpenseClaimsNavigationController" }
    static var storyboardIdentifier: String? { return "ExpenseClaimsNavigationController" }
}

Specifically the public var. The exact error is: Cannot declare a public var in an extension with internal requirements

This is the relevant class:

class RotatingNavigationController: UINavigationController {
    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return [.portrait, .landscape]
    }
}

class LeaveAttachmentNavigationController: RotatingNavigationController {}
class ExpenseClaimsNavigationController: RotatingNavigationController {}

Strangely I don't have this issue in another project, the public keyword is not present. Am I doing something wrong or is this an issue with Natalie?

phimage commented 6 years ago

I already see this issue. We put public for some case

your controller come from a framework?

the code which produce the code

if isCurrentModule {
     // Accessors for view controllers defined in the current module should be "internal".
     output += "    var storyboardIdentifier: \(os.storyboardSceneIdentifierType)? { return \(initIdentifierString) }\n"
} else {
   // Accessors for view controllers in external modules (whether system or custom frameworks), should be marked public.
  output += "    public var storyboardIdentifier: \(os.storyboardSceneIdentifierType)? { return \(initIdentifierString) }\n"
}

with storyboardCustomModules list of module found in storyboards

var isCurrentModule = false
if let customModule = viewController.customModule {
   isCurrentModule = !storyboardCustomModules.contains(customModule)
}
aspyre commented 6 years ago

Interesting, no idea why some of my controllers had the "Inherit Module From Target" checkbox unchecked, but checking it has fixed the issue. Thanks!

Regardless though, it would be good if Natalie could somehow handle this a bit more gracefully if possible, rather than causing compile errors? I don't really understand the details though, so of course this might not be possible.

alkalim commented 6 years ago

I came across this error few days ago too. I may be totally wrong on this but...

no idea why some of my controllers had the "Inherit Module From Target" checkbox unchecked, but checking it has fixed the issue.

It masked the issue by turning off public modifier but the real problem is that Natalie generates type constrained extension for the internal type:

public protocol IdentifiableProtocol: Equatable {
    var storyboardIdentifier: String? { get }
}

...

protocol ViewControllerIdentifiableProtocol: IdentifiableProtocol { }

extension ViewController: ViewControllerIdentifiableProtocol { }

extension IdentifiableProtocol where Self: ViewController {
    public var storyboardIdentifier: String? { return "ViewController" }
    static var storyboardIdentifier: String? { return "ViewController" }
}

IdentifiableProtocol declared as public and by saying "Cannot declare a public var in an extension with internal requirements" Swift probably means that you cannot have default implementation of IdentifiableProtocol with public access modifiers unless the type (ViewController) in the type constraint for the extension (where Self: ViewController) is also made public.

I'm not sure how to fix this and whether this situation avoidable at the Natalie level. Obviously declaring all view controllers and their methods public because of this error isn't a best fix.