1

I'm working on an app in swift which needs to run on all iPhone models from 4S onwards but I want to to be laid out very differently on 4S, so I want to direct the app to load into a completely different storyboard on 4S. I know this can be done for iPad in the info tab but setting the Main storyboard file base name (iPad) but I cannot find a way to do this for different iPhone models. Any help would be greatly appreciated

D.Plumm
  • 11
  • 1
  • 2
  • If you are working in Swift, it would be better wo use SizeClasses of your Storyboard, than using different Storyboards – Dennis Weidmann Aug 30 '15 at 19:28
  • As far as I know, you don't even have to use Swift to use Size Classes, you only need Xcode 6 or higher – Yannik Aug 30 '15 at 19:37
  • I've been using size classes to constrain for iPhone 5 onwards but I'm looking for a way to have something that looks completely different running on 4s – D.Plumm Aug 30 '15 at 19:48
  • Check out http://stackoverflow.com/questions/14672023/selecting-different-storyboards-based-on-device-type – Kendel Aug 30 '15 at 19:50
  • Thank you, I've read that question and tired to implement that solution with no success. I was hoping for a way to choose which storyboard loads using code after identifying which device it is running on with the method used in the seconds answer to this [question](http://stackoverflow.com/questions/24059327/detect-current-device-with-ui-user-interface-idiom-in-swift) – D.Plumm Aug 30 '15 at 20:23
  • You can check my answer here: http://stackoverflow.com/questions/25855055/iphone-6-a-different-storyboard/26084863#26084863 – bpolat Aug 30 '15 at 21:13

2 Answers2

2

Hi I think you can achieve this by programmatically loading different storyboard based on iPhone model

You can use storyboard for any devices models not just iPad or generic iPhone alone.

First check out this link how to determine device type

That's the first think came up on search , you can able to find it, it not let me know will post code

Then you can load device specific storyboard like below

let storyboard: UIStoryboard
If 4s {
storyboard = UIStoryboard(name:"Main_4s.storyboard", bundle: NSBundle.mainBundle())
} else {
storyboard = UIStoryboard(name:"Main_default.storyboard", bundle: NSBundle.mainBundle())
}
let nc = storyboard.instantiateViewControllerWithIdentifier("navController")

then set the navigation controller as the root view controller in the main UI window

UIApplication.sharedApplication().keyWindow?.rootViewContoller = nc 

Note: I haven't tried this yet!

Community
  • 1
  • 1
Ramesh Lingappa
  • 2,448
  • 20
  • 33
  • Your method seems to work great, would it be possible for you to show me how to make the story boards start on a normal view controller called "FirstLaunch" instead of going thorough a navigation controller? – D.Plumm Aug 30 '15 at 22:21
  • Instantiate the view controller with identifier "FirstLaunch" and set it as an root view controller , you can you any view controller as root view controller – Ramesh Lingappa Aug 31 '15 at 05:11
2

Following the very good answer of @HAS here, you can know the model of the device. Let's make a swift file entitled DeviceModel to keep the parts of the extension separated.

DeviceModel.swift

import UIKit

private let DeviceList = [
                          /* iPod 5 */          "iPod5,1": "iPod Touch 5",
                          /* iPhone 4 */        "iPhone3,1":  "iPhone 4", "iPhone3,2": "iPhone 4", "iPhone3,3": "iPhone 4",
                          /* iPhone 4S */       "iPhone4,1": "iPhone 4S",
                          /* iPhone 5 */        "iPhone5,1": "iPhone 5", "iPhone5,2": "iPhone 5",
                          /* iPhone 5C */       "iPhone5,3": "iPhone 5C", "iPhone5,4": "iPhone 5C",
                          /* iPhone 5S */       "iPhone6,1": "iPhone 5S", "iPhone6,2": "iPhone 5S",
                          /* iPhone 6 */        "iPhone7,2": "iPhone 6",
                          /* iPhone 6 Plus */   "iPhone7,1": "iPhone 6 Plus",
                          /* iPad 2 */          "iPad2,1": "iPad 2", "iPad2,2": "iPad 2", "iPad2,3": "iPad 2", "iPad2,4": "iPad 2",
                          /* iPad 3 */          "iPad3,1": "iPad 3", "iPad3,2": "iPad 3", "iPad3,3": "iPad 3",
                          /* iPad 4 */          "iPad3,4": "iPad 4", "iPad3,5": "iPad 4", "iPad3,6": "iPad 4",
                          /* iPad Air */        "iPad4,1": "iPad Air", "iPad4,2": "iPad Air", "iPad4,3": "iPad Air",
                          /* iPad Air 2 */      "iPad5,1": "iPad Air 2", "iPad5,3": "iPad Air 2", "iPad5,4": "iPad Air 2",
                          /* iPad Mini */       "iPad2,5": "iPad Mini", "iPad2,6": "iPad Mini", "iPad2,7": "iPad Mini",
                          /* iPad Mini 2 */     "iPad4,4": "iPad Mini", "iPad4,5": "iPad Mini", "iPad4,6": "iPad Mini",
                          /* iPad Mini 3 */     "iPad4,7": "iPad Mini", "iPad4,8": "iPad Mini", "iPad4,9": "iPad Mini",
                          /* Simulator */       "x86_64": "Simulator", "i386": "Simulator"
                         ]

public extension UIDevice {

    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)

        let machine = systemInfo.machine
        let mirror = reflect(machine)                // Swift 1.2
        // let mirror = Mirror(reflecting: machine)  // Swift 2.0
        var identifier = ""

        // Swift 1.2 - if you use Swift 2.0 comment this loop out.
        for i in 0..<mirror.count {
            if let value = mirror[i].1.value as? Int8 where value != 0 {
                identifier.append(UnicodeScalar(UInt8(value)))
            }
        }

        // Swift 2.0 and later - if you use Swift 2.0 uncomment his loop
        // for child in mirror.children where child.value as? Int8 != 0 {
        //     identifier.append(UnicodeScalar(UInt8(child.value as! Int8)))
        // }

        return DeviceList[identifier] ?? identifier
    }
}

Then in your AppDelegate.swift inside your didFinishLaunchingWithOptions you can instantiate the Storyboard regarding the device model, like in the following way:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    var storyboard: UIStoryboard

    // instantiate the `UIWindow`
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

    // Get the model name based in the extension.
    let modelName = UIDevice.currentDevice().modelName

    // If the modelName variable contains the string "iPhone 6" inside.
    if (modelName.rangeOfString("iPhone 6") != nil) {
        storyboard = UIStoryboard(name: "iPhone6Storyboard", bundle: nil)
        self.window!.rootViewController = storyboard.instantiateInitialViewController() as! iPhone6ViewController
    }
    else if (modelName.rangeOfString("iPad") != nil) {
        storyboard = UIStoryboard(name: "iPadStoryboard", bundle: nil)
        self.window!.rootViewController = storyboard.instantiateInitialViewController() as! iPadViewController
    }

    self.window!.makeKeyAndVisible()

    return true
}

To the above code works if you have added the UIStoryboard's you need, set for each UIStoryboard its initial UIViewController using Interface Builder(in the case you don't want to set the initial UIViewController using Interface Builder, you can find very easy how to set the initial UIViewController programmatically, but purpose of brevety I've used Interface Builder).

Of course you need to in the app's setting, go to your target and the Info tab. There clear the value of Main storyboard file base name. On the General tab, clear the value for Main Interface. You can read more about it in this answer Programmatically set the initial view controller using Storyboards.

You need to take care with two things:

  • In the Simulator you can't test the device models code(it only give you 'Simulator'), you need real devices.
  • You need to play with the devices name properly according the code in the DeviceModel.swift to match the different names.

For the sake of brevety I only put two devices above, but in any case you need to match any device model you want according the names.

I hope this help you.

Community
  • 1
  • 1
Victor Sigler
  • 23,243
  • 14
  • 88
  • 105