How to subclass UITableViewController in Swift

后端 未结 9 1821
栀梦
栀梦 2020-12-23 11:42

I want to subclass UITableViewController and be able to instantiate it by calling a default initializer with no arguments.

class TestViewController: UITableV         


        
相关标签:
9条回答
  • 2020-12-23 12:01

    matt's answer is the most complete, but if you do want to use a tableViewController in the .plain style (say for legacy reasons). Then all you need to do is call

    super.init(nibName: nil, bundle: nil)

    instead of

    super.init(style: UITableViewStyle.Plain) or self.init(style: UITableViewStyle.Plain)

    0 讨论(0)
  • 2020-12-23 12:03

    I did it like this

    class TestViewController: UITableViewController {
    
        var dsc_var: UITableViewController?
    
        override convenience init() {
            self.init(style: .Plain)
    
            self.title = "Test"
            self.clearsSelectionOnViewWillAppear = true
        }
    }
    

    Creating and displaying a instance of TestViewController in a UISplitViewController did work for me with this code. Maybe this is bad practice, please tell me if it is (just started with swift).

    For me there's still a problem when there are non optional variables and the solution of Nick Snyder is the only one working in this situation
    There's just 1 problem: The variables are initialized 2 times.

    Example:

    var dsc_statistcs_ctl: StatisticsController?
    
    var dsrc_champions: NSMutableArray
    
    let dsc_search_controller: UISearchController
    let dsrc_search_results: NSMutableArray
    
    
    override init() {
        dsrc_champions = dsrg_champions!
    
        dsc_search_controller = UISearchController(searchResultsController: nil)
        dsrc_search_results = NSMutableArray.array()
    
        super.init(style: .Plain) // -> calls init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) of this class
    }
    
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        // following variables were already initialized when init() was called and now initialized again
        dsrc_champions = dsrg_champions!
    
        dsc_search_controller = UISearchController(searchResultsController: nil)
        dsrc_search_results = NSMutableArray.array()
    
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    0 讨论(0)
  • 2020-12-23 12:06

    Xcode 6 Beta 5

    It appears that you can no longer declare a no-argument convenience initializer for a UITableViewController subclass. Instead, you need to override the default initializer.

    class TestViewController: UITableViewController {
        override init() {
            // Overriding this method prevents other initializers from being inherited.
            // The super implementation calls init:nibName:bundle:
            // so we need to redeclare that initializer to prevent a runtime crash.
            super.init(style: UITableViewStyle.Plain)
        }
    
        // This needs to be implemented (enforced by compiler).
        required init(coder aDecoder: NSCoder!) {
            // Or call super implementation
            fatalError("NSCoding not supported")
        }
    
        // Need this to prevent runtime error:
        // fatal error: use of unimplemented initializer 'init(nibName:bundle:)'
        // for class 'TestViewController'
        // I made this private since users should use the no-argument constructor.
        private override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        }
    }
    
    0 讨论(0)
  • 2020-12-23 12:10

    I wanted to subclass UITableViewController and add a non-optional property which requires overriding the initializer and dealing with all the problems described above.

    Using a Storyboard and a segue gives you more options if you can work with an optional var rather than a non-optional let in your subclass of UITableViewController

    By calling performSegueWithIdentifier and overriding prepareForSegue in your presenting view controller, you can get the instance of the UITableViewController subclass and set the optional variables before initialization is completed:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
            if segue.identifier == "segueA"{
                var viewController : ATableViewController = segue.destinationViewController as ATableViewController
                viewController.someVariable = SomeInitializer()
            }
    
            if segue.identifier == "segueB"{
                var viewController : BTableViewController = segue.destinationViewController as BTableViewController
                viewController.someVariable = SomeInitializer()
            }
    
        }
    
    0 讨论(0)
  • 2020-12-23 12:11

    Props to matt for a great explanation. I've made use of both matt's and @Nick Snyder's solutions, however I ran into a case in which neither would quite work, because I needed to (1) initialize let fields, (2) use init(style: .Grouped) (without getting a runtime error), and (3) use the built-in refreshControl (from UITableViewController). My workaround was to introduce an intermediate class MyTableViewController in ObjC, then use that class as the base of my table view controllers.

    MyTableViewController.h

    #import <UIKit/UIKit.h>
    // extend but only override 1 designated initializer
    @interface MyTableViewController : UITableViewController
    - (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
    @end
    

    MyTableViewController.m:

    #import "MyTableViewController.h"
    // clang will warn about missing designated initializers from
    // UITableViewController without the next line.  In this case
    // we are intentionally doing this so we disregard the warning.
    #pragma clang diagnostic ignored "-Wobjc-designated-initializers"
    @implementation MyTableViewController
    - (instancetype)initWithStyle:(UITableViewStyle)style {
        return [super initWithStyle:style];
    }
    @end
    

    Add the following to Project's Bridging-Header.h

    #import "MyTableViewController.h"
    

    Then use in swift. Example: "PuppyViewController.swift":

    class PuppyViewController : MyTableViewController {
        let _puppyTypes : [String]
        init(puppyTypes : [String]) {
            _puppyTypes = puppyTypes // (1) init let field (once!)
            super.init(style: .Grouped) // (2) call super with style and w/o error
            self.refreshControl = MyRefreshControl() // (3) setup refresh control
        }
        // ... rest of implementation ...
    }
    
    0 讨论(0)
  • 2020-12-23 12:14
    class ExampleViewController: UITableViewController {
        private var userName: String = ""
    
        static func create(userName: String) -> ExampleViewController {
            let instance = ExampleViewController(style: UITableViewStyle.Grouped)
            instance.userName = userName
            return instance
        }
    }
    
    let vc = ExampleViewController.create("John Doe")
    
    0 讨论(0)
提交回复
热议问题