¿Cómo creo un nuevo proyecto Swift sin usar Storyboards?

107

Crear un nuevo proyecto en XCode 6 no permite deshabilitar Storyboards. Solo puede seleccionar Swift u Objective-C y usar o no Core Data.

Intenté eliminar el guión gráfico y del proyecto eliminar el guión gráfico principal y configurar manualmente la ventana desde didFinishLaunching

En AppDelegate tengo esto:

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow
var testNavigationController: UINavigationController

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {

        testNavigationController = UINavigationController()
        var testViewController: UIViewController = UIViewController()
        self.testNavigationController.pushViewController(testViewController, animated: false)

        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

        self.window.rootViewController = testNavigationController

        self.window.backgroundColor = UIColor.whiteColor()

        self.window.makeKeyAndVisible()

        return true
    }
}

Sin embargo, XCode me da un error:

La clase 'AppDelegate' no tiene inicializadores

¿Alguien ha tenido éxito en esto?

EhTd
fuente
1
Posible duplicado de Cómo crear una aplicación vacía en Xcode 6 sin Storyboard
S1LENT WARRIOR

Respuestas:

71

Debe marcar las variables windowy testNavigationControllercomo opcionales:

var window : UIWindow?
var testNavigationController : UINavigationController?

Las clases Swift requieren que se inicialicen propiedades no opcionales durante la instanciación:

Las clases y estructuras deben establecer todas sus propiedades almacenadas en un valor inicial apropiado para cuando se crea una instancia de esa clase o estructura. Las propiedades almacenadas no se pueden dejar en un estado indeterminado.

Las propiedades de tipo opcional se inicializan automáticamente con un valor de nil, lo que indica que se pretende deliberadamente que la propiedad "no tenga valor todavía" durante la inicialización.

Cuando use variables opcionales, recuerde desenvolverlas con !, como:

self.window!.backgroundColor = UIColor.whiteColor();
Akashivskyy
fuente
1
Todo tiene perfecto sentido en tu respuesta, hasta el final. ¿Podrías explicar esa última parte? ¿desenvolver? es esto requerido?
DanMoore
1
No puede almacenar una propiedad no opcional en su AppDelegate(a menos que tenga un valor durante la inicialización o se resuelva de forma perezosa). Si almacena una propiedad opcional y está seguro de que no lo es nil, "desenvuelva su opcionalidad" usando el !operador.
Akashivskyy
cuál es la mejor práctica, self.window! o usando if let window = ..?
Laughingman
1
Si está seguro de que su ventana existe (y puede estar seguro en este caso particular), puede seguir !.
akashivskyy
Entonces, ¿esto significa que cuando usamos guiones gráficos, el color de fondo que de alguna manera fue predeterminado .white?
Miel
91

Todo lo que se necesita para no usar Storyboards para rootViewController:

1 · Cambiar AppDelegate.swifta:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        if let window = window {
            window.backgroundColor = UIColor.white
            window.rootViewController = ViewController()
            window.makeKeyAndVisible()
        }
        return true
    }
}

2 · Cree una ViewControllersubclase de UIViewController:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.blue
    }
}

3 · Si creó el proyecto a partir de una plantilla de Xcode:

  1. Quite el par clave-valor de la clave "Main storyboard file base name"de Info.plist.
  2. Elimina el archivo del guión gráfico Main.storyboard.

Como puede ver en el primer fragmento de código, en lugar de desenvolver implícitamente un opcional, me gusta la if letsintaxis para desenvolver la windowpropiedad opcional . Aquí lo estoy usando así if let a = a { }para que lo opcional se aconvierta en una referencia no opcional dentro de la if-declaración con el mismo nombre- a.

Finalmente, self.no es necesario cuando se hace referencia a la windowpropiedad dentro de su propia clase.

tobiasdm
fuente
1
¿Por qué el if let window = window {? ¡Me lo imaginé! Es por lo que no es necesario usarlo window!todo el tiempo.
Bilal Akil
@ 2unco Me alegra que lo hayas descubierto. Esto se describe en la última parte de mi respuesta sobre if let a = a {}.
tobiasdm
Movería la llamada makeKeyAndVisible()a estar después de configurar rootViewController. De lo contrario, recibirá una advertencia sobre cómo se espera que la ventana tenga un controlador de vista raíz al final del inicio de la aplicación.
Sebastien Martin
if let a = a { }se ve raro. ¿Está seguro de que está bien usar el mismo nombre de variable para la referencia no opcional? Apple siempre usa nombres diferentes en sus documentos Swift. Además, ¿por qué esto es mejor que usarlo window!todo el tiempo?
ma11hew28
1. if let a = a { }está perfectamente bien. Puedes usarlo if let anA = a { }si te hace sentir más cómodo. 2. window!es una comprobación de tiempo de ejecución, ya que desenvuelve explícitamente un archivo. Me gustan las comprobaciones de tiempo de compilación que nos proporciona Swift, así que ¿por qué no usarlas?
tobiasdm
13

Si desea inicializar su viewController con xib y necesita usar el controlador de navegación. Aquí hay un fragmento de código.

var window: UIWindow?
var navController:UINavigationController?
var viewController:ViewController?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    window = UIWindow(frame: UIScreen.mainScreen().bounds)

    viewController = ViewController(nibName: "ViewController", bundle: nil);
    navController = UINavigationController(rootViewController: viewController!);

    window?.rootViewController = navController;
    window?.makeKeyAndVisible()

    return true
}
Warewolf
fuente
6

Prueba el siguiente código:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    self.window!.backgroundColor = UIColor.whiteColor()

    // Create a nav/vc pair using the custom ViewController class

    let nav = UINavigationController()
    let vc = NextViewController ( nibName:"NextViewController", bundle: nil)

    // Push the vc onto the nav
    nav.pushViewController(vc, animated: false)

    // Set the window’s root view controller
    self.window!.rootViewController = nav

    // Present the window
    self.window!.makeKeyAndVisible()
    return true

}
PREMKUMAR
fuente
2

Encontré que la respuesta no tenía nada que ver con la configuración de xcode, eliminar el guión gráfico y la referencia del proyecto es lo correcto. Tenía que ver con la sintaxis rápida.

El código es el siguiente:

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
var testNavigationController: UINavigationController?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {

        self.testNavigationController = UINavigationController()
        var testViewController: UIViewController? = UIViewController()
        testViewController!.view.backgroundColor = UIColor.redColor()
        self.testNavigationController!.pushViewController(testViewController, animated: false)

        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

        self.window!.rootViewController = testNavigationController

        self.window!.backgroundColor = UIColor.whiteColor()
        self.window!.makeKeyAndVisible()

        return true
    }

}
EhTd
fuente
Pero, ¿por qué responder a su propia pregunta, si la solución está en otra respuesta?
Akashivskyy
la página no se actualizó y no vi la respuesta, solo después de la publicación
EhTd
2

Puedes hacerlo así:

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var IndexNavigationController: UINavigationController?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        var IndexViewContoller : IndexViewController? = IndexViewController()
        self.IndexNavigationController = UINavigationController(rootViewController:IndexViewContoller)
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window!.rootViewController = self.IndexNavigationController
        self.window!.backgroundColor = UIColor.whiteColor()
        self.window!.makeKeyAndVisible()
        return true
    }
}
Hilen
fuente
¿Var window: UIWindow? especificar que es una propiedad opcional?
Sean Dunford
Bueno, solo intenté agregar una segunda var en el delegado de la aplicación sin ella y descubrí que mi declaración anterior era cierta.
Sean Dunford
2

Te recomiendo que uses controller y xib

MyViewController.swift y MyViewController.xib

(Puede crear a través de Archivo-> Nuevo-> Archivo-> Clase Cocoa Touch y establecer "también crear archivo XIB" verdadero, subclase de UIViewController)

class MyViewController: UIViewController {
   .....    
}

y en AppDelegate.swift func applicationescribir el siguiente código

....
var controller: MyViewController = MyViewController(nibName:"MyViewController",bundle:nil)
self.window!.rootViewController = controller
return true

¡Debería ser trabajo!

Yi Feng Xie
fuente
Intenté de la misma manera que mencionaste, pero error: terminando la aplicación debido a una excepción no detectada 'NSInternalInconsistencyException', motivo: 'No se pudo cargar NIB en el paquete:
shripad20
2

Actualizado para Swift 3.0:

window = UIWindow()
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
Tiago Martinho
fuente
2

Actualización: Swift 5 y iOS 13:

  1. Cree una aplicación de vista única.
  2. Eliminar Main.storyboard (clic derecho y eliminar).
  3. Elimine el nombre del guión gráfico de la configuración de escena predeterminada en el Info.plistarchivo:ingrese la descripción de la imagen aquí
  4. Abrir SceneDelegate.swifty cambiar func scenede:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let _ = (scene as? UIWindowScene) else { return }
}

a

 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).x

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = ViewController()
        self.window = window
        window.makeKeyAndVisible()
    }
}
Jogendra Kumar
fuente
1

Aquí hay un ejemplo de prueba rápido completo para un UINavigationController

        import UIKit
        @UIApplicationMain
        class KSZAppDelegate: UIResponder, UIApplicationDelegate {    
          var window: UIWindow?
          var testNavigationController: UINavigationController?

          func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Override point for customization after application launch.        
            // Working WITHOUT Storyboard
            // see http://randexdev.com/2014/07/uicollectionview/
            // see http://stackoverflow.com/questions/24046898/how-do-i-create-a-new-swift-project-without-using-storyboards
            window = UIWindow(frame: UIScreen.mainScreen().bounds)
            if let win = window {
              win.opaque = true    
            //you could create the navigation controller in the applicationDidFinishLaunching: method of your application delegate.    
              var testViewController: UIViewController = UIViewController()
              testNavigationController = UINavigationController(rootViewController: testViewController)
              win.rootViewController = testNavigationController
              win.backgroundColor = UIColor.whiteColor()
              win.makeKeyAndVisible()
// see corresponding Obj-C in https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html#//apple_ref/doc/uid/TP40011313-CH2-SW1
        //      - (void)applicationDidFinishLaunching:(UIApplication *)application {
        //    UIViewController *myViewController = [[MyViewController alloc] init];
        //    navigationController = [[UINavigationController alloc]
        //                                initWithRootViewController:myViewController];
        //    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        //    window.rootViewController = navigationController;
        //    [window makeKeyAndVisible];
            //}
            }
            return true
          }
    }
Dmitry Konovalov
fuente
0

¿Por qué no crea una aplicación vacía? el storyboard no me fue creado ...

allemattio
fuente
0

Podemos crear una aplicación basada en navegación sin guión gráfico en Xcode 6 (iOS 8) de la siguiente manera:

  • Cree una aplicación vacía seleccionando el idioma del proyecto como Swift.

  • Agregue nuevos archivos de clases de cocoa touch con la interfaz xib. (por ejemplo, TestViewController)

  • En el swift, solo tenemos un archivo que interactúa con el archivo xib, es decir, * .swift, no hay archivos .hy .m.

  • Podemos conectar los controles de xib con un archivo rápido igual que en iOS 7.

A continuación se muestran algunos fragmentos para trabajar con los controles y Swift

//
//  TestViewController.swift
//

import UIKit

class TestViewController: UIViewController {

    @IBOutlet var testBtn : UIButton

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // Custom initialization
    }

    @IBAction func testActionOnBtn(sender : UIButton) {
        let cancelButtonTitle = NSLocalizedString("OK", comment: "")

        let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)

        // Create the action.
        let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .Cancel) { action in
            NSLog("The simple alert's cancel action occured.")
        }

        // Add the action.
        alertController.addAction(cancelAction)

        presentViewController(alertController, animated: true, completion: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

Cambios en el archivo AppDelegate.swift

//
//  AppDelegate.swift
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    var navigationController: UINavigationController?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window!.backgroundColor = UIColor.whiteColor()
        self.window!.makeKeyAndVisible()

        var testController: TestViewController? = TestViewController(nibName: "TestViewController", bundle: nil)
        self.navigationController = UINavigationController(rootViewController: testController)
        self.window!.rootViewController = self.navigationController

        return true
    }

    func applicationWillResignActive(application: UIApplication) {
}

    func applicationDidEnterBackground(application: UIApplication) {
    }

    func applicationWillEnterForeground(application: UIApplication) {
    }

    func applicationDidBecomeActive(application: UIApplication) {
    }

    func applicationWillTerminate(application: UIApplication) {
    }

}

Encuentre ejemplos de código y otra información en http://ashishkakkad.wordpress.com/2014/06/16/create-a-application-in-xcode-6-ios-8-without-storyborard-in-swift-language-and -trabajar-con-controles /

Ashish Kakkad
fuente
0

En iOS 13 y superior, cuando cree un nuevo proyecto sin guión gráfico, utilice los siguientes pasos:

  1. Cree un proyecto usando Xcode 11 o superior

  2. Eliminar la plumilla y la clase del guión gráfico

  3. Agregar nuevo archivo nuevo con xib

  4. Necesita establecer la vista raíz como UINavigationController SceneDelegate

  5. agregue el siguiente código func scene (_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {// Use este método para configurar y adjuntar opcionalmente la UIWindow windowa la UIWindowScene proporcionada scene. // Si usa un guión gráfico, la windowpropiedad se inicializará automáticamente y se adjuntará a la escena. // Este delegado no implica que la escena o sesión de conexión sea nueva (ver en su application:configurationForConnectingSceneSessionlugar). // guard let _ = (escena como? UIWindowScene) else {return}

    si deja windowScene = escena como? UIWindowScene {self.window = UIWindow (windowScene: windowScene) deja mainController = HomeViewController () como HomeViewController deja que navigationController = UINavigationController (rootViewController: mainController) self.window! .RootViewController = navigationController self.window! .Make}

Yogesh Shelke
fuente