7 Replies
      Latest reply on Aug 13, 2019 7:19 AM by Thomas E.
      sagits Level 1 Level 1 (0 points)

        Hi, im trying to load a class that extends a generic uiViewController in a storyboard. But if the super usesgenerics (T), the storyboard cant recognize the class (wont even autocomplete)  and give me "... class not found" error. More info at http://stackoverflow.com/questions/32836343/generic-controller-in-swift-2-0-using-storyboards

         

        Anyone can help? Thanks in advance.

        • Re: Generic controller with storyboard
          ahurlburt Level 1 Level 1 (0 points)

          I was wondering if you ever found an answer to this?

           

          I see many stack overflows describing the same problem and provide the reason that this is not possible being that interface builder uses the obj-c runtime.

           

          I have been burned by this several times in my app and need to produce (in my mind) unnecessary code because of it. Until generic classes are supported in storyboards it really limits the use of generics which is frustrating because generics are so useful for producing cleaner code.

           

          I am posting here to hopefully gain some visibility for apple engineers (who I realize are probably already well aware of this), maybe this is something coming in the future? Like I said there are alot of stack overflows about this. If swift is the future seems like interface builder should maybe make use of it (and support all it's functions)?

            • Re: Generic controller with storyboard
              eskimo Apple Staff Apple Staff (11,655 points)

              I got this work actually

              That’s a neat trick.  Some comments:

              • You don’t need to instantiate the derived class; any reference to it will do.  Removing that instantiation makes the view controller code much simpler.

              • If the derived class is referenced by the main storyboard, you need to make sure you ‘touch’ it before UIApplicationMain runs.

              To test this I first started with an obvious generic view controller.

              class BaseViewController<Element>: UITableViewController {
              
                  var content: [Element] = []
              
                  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                      return self.content.count
                  }
              
                  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                      let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
                      cell.textLabel!.text = "\(self.content[indexPath.row])"
                      return cell
                  }
              }
              

              I then specialised it for the sake of IB.

              class DerivedViewController : BaseViewController<String> {
              }
              

              I then set up my main storyboard to reference it and modified application(_:didFinishLaunchingWithOptions:) to set it up.

              func application(… didFinishLaunchingWithOptions …) -> Bool {
                  let nav = self.window?.rootViewController! as! UINavigationController
                  let derived = nav.topViewController! as! DerivedViewController
                  derived.content = ["Hello", "Cruel", "World"]
                  return true
              }
              

              Finally, I removed @UIApplicationMain from my AppDelegate and replaced it with a main.swift as shown below.

              import UIKit
              
              print(DerivedViewController.self)
              
              // The following is required because there's an impedence mismatch between
              // `CommandLine` and `UIApplicationMain` <rdar://problem/25693546>.
              let argv = UnsafeMutableRawPointer(CommandLine.unsafeArgv).bindMemory( 
                  to: UnsafeMutablePointer<Int8>.self, 
                  capacity: Int(CommandLine.argc)
              )
              UIApplicationMain(CommandLine.argc, argv, nil, NSStringFromClass(AppDelegate.self))
              

              The magic is in line 3, which touches the DerivedViewController class and thereby makes it available to the Objective-C runtime.  The rest of the stuff is boilerplate, made more difficult by the above-mentioned bug.


              Clearly this sort of workaround shouldn’t be necessary.  I presumed that folks have filed bugs about this.  If you have the bug number handy, please post it, just for my records.

              Share and Enjoy

              Quinn “The Eskimo!”
              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
              let myEmail = "eskimo" + "1" + "@apple.com"

                • Re: Generic controller with storyboard
                  iofluxdev1 Level 1 Level 1 (0 points)

                  Thanks for your suggested solution, it did however not resolve my issues with the storyboard GUI and generic super classes. Sad to see it is 2019 and it is still an issue >.>

                    • Re: Generic controller with storyboard
                      Claude31 Level 8 Level 8 (6,385 points)

                      Would you explain what are precisely those issues with the storyboard GUI and generic super classes ?

                       

                      Are they the same as in the OP ?

                      • Re: Generic controller with storyboard
                        eskimo Apple Staff Apple Staff (11,655 points)

                        it did however not resolve my issues with the storyboard GUI and generic super classes

                        I just re-tested the example I posted and it works for me (Xcode 10.2 targeting the iOS 12.2 simulator).  Perhaps you could explain more about the specific problems you’re seeing?

                        Share and Enjoy

                        Quinn “The Eskimo!”
                        Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                        let myEmail = "eskimo" + "1" + "@apple.com"

                          • Re: Generic controller with storyboard
                            Thomas E. Level 1 Level 1 (0 points)

                            Well, I assume the OP refers to issues like as soon as the generics derived class is not "automatically" exposed via the Objective-C runtime, the IBOutlets aren't exposed either:

                              

                            class DescriptionHeaderController:
                                UIViewController
                                where ModelType: NSManagedObject, ModelType: ModelAdapterFactory
                            {
                                var model : ModelType!
                                
                                // No chance to set in IB:    
                                @IBOutlet weak var ratingContainerView: UIView! 
                            }
                            
                            class DerivedHeaderController : DescriptionHeaderController<Foo> {
                            }

                             

                            (Just hitting that roadblock after sorting out protocols with associated type and quite a lot of other issues..)