user1591668
user1591668

Reputation: 2893

IOS Swift How can I have an enum return different classes

I was wondering if there is a way to have an enum and assign it different values from different classes for instance, I have 3 classes that instantiate a View Controller and I always start them like this

let placeAreaC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PlaceAreaC") as! PlaceAreaC

let notificationC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NotificationC") as! NotificationC

let reportC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ReportC") as! ReportC

Each time I want to go to a new controller I have to do that, I was wondering if I can create an enum that can hold those values, right now I have this code

class ControllerEnum: NSObject {
    
    enum InstantiateEnum: String {
        case Report = "Report" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ReportC") as! ReportC
        case Notification = "Notification" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NotificationC") as! NotificationC
        case PlaceArea = "PlaceArea" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ReportC") as! ReportC
        
    }
  }

I know the type is String but I am wondering how can I make it so that the type accepts those 3 different classes above ? So that then I can reference them doing something like

InstantiateEnum.Notification

That would be very useful because now I can change those values in just 1 place . Any suggestions would be great .

Upvotes: 0

Views: 2650

Answers (2)

Prashant Tukadiya
Prashant Tukadiya

Reputation: 16426

You can have property that return ViewController in your enum

enum InstantiateEnum: String {
    case Report = "Report" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ReportC") as! ReportC
    case Notification = "Notification" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NotificationC") as! NotificationC
    case PlaceArea = "PlaceArea" // UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ReportC") as! ReportC

   var viewController:UIViewController {
       switch self  {
           case  Report :
             return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: self.rawValue)
           ...

       }

   }

}

OR

You can have one class Method in each of your View Controller return self object

like

class func viewController() -> ReportC {
    return StoryBoard.main.instantiateViewController(withIdentifier: StoryBoard.controller.ReportC) as! ReportC
}

And create Constants of Your Identifier

struct StoryBoard {

    static let main = UIStoryboard.init(name: "Main", bundle: nil)
    static let otherStoryboard = UIStoryboard.init(name: "otherStoryboard", bundle: nil)

    struct controller {
        static let ReportC                                  =   "Report"
     }
}

Upvotes: 1

Pramod Kumar
Pramod Kumar

Reputation: 2652

There is better way that I used:

Step 1: Just Copy this enum with extensions. And change the storyboards name with those you have in your project

enum AppStoryboard : String {

case Main
case Notification
case Profile
case Login
}

extension AppStoryboard {

var instance : UIStoryboard {

    return UIStoryboard(name: self.rawValue, bundle: Bundle.main)
}

func viewController<T : UIViewController>(viewControllerClass : T.Type, function : String = #function, line : Int = #line, file : String = #file) -> T {

    let storyboardID = (viewControllerClass as UIViewController.Type).storyboardID

    guard let scene = instance.instantiateViewController(withIdentifier: storyboardID) as? T else {

        fatalError("ViewController with identifier \(storyboardID), not found in \(self.rawValue) Storyboard.\nFile : \(file) \nLine Number : \(line) \nFunction : \(function)")
    }

    return scene
}

func initialViewController() -> UIViewController? {

    return instance.instantiateInitialViewController()
}
}

extension UIViewController {

  // Not using static as it wont be possible to override to provide custom storyboardID then
class var storyboardID : String {

    return "\(self)"
}

static func instantiate(fromAppStoryboard appStoryboard: AppStoryboard) -> Self {

    return appStoryboard.viewController(viewControllerClass: self)
} }

Step 2: Assign the storyboard id same as the class name of the view controller in storyboard.

Step 3: Now create the object of the viewcontroller like:

let notificationVC = NotificationVC.instantiate(fromAppStoryboard: .Notification)

/* Syntax:
let <yourObject> = <YourViewController's class name>.instantiate(fromAppStoryboard: <respected storyboard>) */

notificationVC will be the objet of type NotificationVC

Now play with your object. :)

Upvotes: 0

Related Questions