Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface Builder: Typed segues on a per scene basis #364

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

djbe
Copy link
Member

@djbe djbe commented Dec 10, 2017

Transfer PRs SwiftGen/SwiftGenKit#54 and SwiftGen/templates#79.
Fixes #362.

SwiftgenKit Changes

This PR improves the storyboards parser in 2 ways:

  • Know which segues start from which scenes
  • Know the type information for a segue destination
    The PR also refactors the Storyboards parser a bit (split up in files).

Templates Changes

Uses the improvements added in SwiftGenKit to generate extensions for non-base classes (UIKit/AppKit), so that a user can:

  • Perform a segue safely with an enum of segues that start from that scene (you can no longer incorrectly start a segue from a VC that doesn't support it).
  • Prepare for a segue in a type safe way:
    • Have an exhaustive list of possible cases, including one for unnamed segues.
    • Get the segue's destination in the correct type (no need to cast it).
    • Get the segue itself as the correct subclass if you're using custom segues.

For performing a segue, the user goes from:

perform(segue: StoryboardSegue.MyStoryboard.nextStep)

To:

perform(segue: .nextStep)

For preparing for a segue, the user goes from:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  // autocomplete for cases won't work because of optionals
  switch segueEnum {
  case .nextStep?:
    guard let destination = segue.destination as? NextStepViewController else { return }
    // destination is casted version
  case .login?:
    guard let destination = segue.destination as? LoginViewController else { return }
    // destination is casted version
  default:
    // Handle segues that are for other scenes, or unnamed segues
  }
}

To:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  switch TypedStoryboardSegue(segue: segue) {
  case .nextStep(let destination):
    // destination is casted version
  case .login(let destination):
    // destination is casted version
  case .unnamedSegue:
    // This case is added if you have unnamed segues (with identifier "")
  }
}

@djbe
Copy link
Member Author

djbe commented Dec 10, 2017

@AliSoftware proposed another idea, that we could add to this template (or an alternative one):

protocol MyViewControllerTypedStoryboardSegue {
  func prepareSegueForEmbed(destination: EmbedDestinationVC)
  func prepareSegueForModal(destination: ModalDestionationVC)func prepare(for segue: NSStoryboardSegue, sender: Any?)
}
extension MyViewControllerTypedStoryboardSegue {
  func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    /* generate that switch/case implementation here which calls the proper prepareSegueForXXX(destionation:) method */
  }
}

There could be issues here because of @objc dispatch and stuff, but could be interesting.

Another proposal was:

/* Generated by SwiftGen */
protocol MyViewControllerTypedStoryboardSegue {
  func prepareSegueForEmbed(destination: EmbedDestinationVC)
  func prepareSegueForModal(destination: ModalDestionationVC)func prepare(for segue: NSStoryboardSegue)
}
extension MyViewControllerTypedStoryboardSegue {
  func prepare(for segue: NSStoryboardSegue) {
    /* generate that switch/case implementation here which calls
        the proper prepareSegueForXXX(destionation:) method */
  }
}

/* Added by the user */
extension MyViewController: MyViewControlelrTypedStoryboardSegue {
  @objc func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    self.prepare(for: segue)
  }
}

I'd probably rename the function here, because users want access to the sender argument so we'd need to pass it along.

@djbe djbe self-assigned this Dec 10, 2017
@parallaxe
Copy link

To know where the segues originate from would be a killer-feature for me to use SwiftGen. I have no opinion regarding the templates though.
Is it foreseeable that it will be merged soon? Is there something I could do to accelerate it?

@djbe
Copy link
Member Author

djbe commented Jan 16, 2018

To begin with: any and all suggestions are welcome!

You could try mock-generating the code (manually) for one of your projects (or just 1 storyboard), and see if the generated code works for you? Are all features there that you might want? Does the functionality match with your project structure?

Maybe go through your project's current segues, their names and controller types, and whatever else you need when performing segues. See if there might be an issue (or not) with the generated code.

return "/document/scenes/scene/objects/*[@sceneMemberID=\"viewController\" and @id=\"\(identifier)\"]"
}
static let sceneXPath = "/document/scenes/scene/objects/*[@sceneMemberID=\"viewController\"]"
static let sceneSegueXPath = "//connections/segue"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding, the StoryboardSegue-enum that is created inside the extensions of each custom Scene-class should only contain the segues that are started from that specific scene.
If this is the case, the xpath has to be "./connections/segue"

Copy link
Member Author

@djbe djbe Apr 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for the // in sceneSegueXPath is to be able to match segues started from (for example):

  • container views --> embed segues
  • triggered by a button or cell

sceneSegueXPath is only used to match children of a scene object:
https://github.com/SwiftGen/SwiftGen/pull/364/files#diff-aab03c1cbf39dc54bf61cfae345dfc87R43

@parallaxe
Copy link

I made a reduced-version of your storyboard-template which contains only the scene-extensions with an segue-enum containing all segues that are started from the scene. Essentially, that is all i would need for know. You can find it here https://gist.github.com/parallaxe/7815fc6a8ed98e2e66de20d65169d608
Though, to make it work as I expected it, I had to change one of the XPaths in the storyboard-parser - I added a comment to the specific line in the "File Changes"-part of the merge-request.

@djbe djbe force-pushed the feature/scene-segues branch 2 times, most recently from 02a5d87 to 7d26ace Compare March 20, 2018 11:41
@djbe djbe force-pushed the feature/scene-segues branch 6 times, most recently from 1fc7c46 to 8db1272 Compare April 29, 2018 14:44
@djbe djbe force-pushed the feature/scene-segues branch 8 times, most recently from 69271ce to e75cd78 Compare May 5, 2018 17:02
@djbe djbe added this to the Swiftgen 6.0 milestone May 6, 2018
@djbe djbe added this to In progress in SwiftGen 6.0 May 6, 2018
@djbe djbe moved this from In progress to To do in SwiftGen 6.0 May 7, 2018
@domasn
Copy link

domasn commented May 1, 2019

Hi all 👋

@djbe thank you for this PR! I think it would be really valuable to a lot of users. I see that you add new commits from time to time and wonder what's the state of this feature?

It there anything I can do to help? 🙂

@djbe djbe force-pushed the feature/scene-segues branch 2 times, most recently from 2564b13 to 413d0c8 Compare June 24, 2020 16:06
@djbe djbe force-pushed the feature/scene-segues branch 5 times, most recently from eeb8043 to 68027db Compare July 6, 2020 18:35
@djbe djbe modified the milestones: 6.3.0, 6.4.0 Jul 6, 2020
@djbe djbe force-pushed the feature/scene-segues branch 2 times, most recently from 11b51f9 to 24a8a3e Compare October 5, 2020 10:14
@djbe djbe modified the milestones: 6.5.0, Next minor (new features) Oct 7, 2020
@djbe djbe marked this pull request as draft April 12, 2021 00:29
- info about segue destinations
- user defined types, and the segues starting from them
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
SwiftGen 6.0
  
To do
Development

Successfully merging this pull request may close these issues.

None yet

5 participants