Jak utworzyć nowy projekt Swift bez używania scenorysów?

107

Tworzenie nowego projektu w XCode 6 nie pozwala na wyłączenie scenorysów. Możesz wybrać tylko Swift lub Objective-C i użyć lub nie Core Data.

Próbowałem usunąć scenorys iz projektu usuwając główny scenorys i ręcznie ustawiając okno z didFinish Uruchamianie

W AppDelegate mam to:

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
    }
}

Jednak XCode daje mi błąd:

Klasa „AppDelegate” nie ma inicjatorów

Czy komuś się to udało?

EhTd
źródło

Odpowiedzi:

71

Musisz oznaczyć zmienne windowi testNavigationControllerjako opcjonalne:

var window : UIWindow?
var testNavigationController : UINavigationController?

Klasy Swift wymagają, aby podczas tworzenia instancji zostały zainicjowane właściwości, które nie są opcjonalne:

Klasy i struktury muszą ustawić wszystkie swoje przechowywane właściwości na odpowiednią wartość początkową do czasu utworzenia wystąpienia tej klasy lub struktury. Nie można pozostawić przechowywanych właściwości w stanie nieokreślonym.

Właściwości typu opcjonalnego są automatycznie inicjowane wartością nil, co oznacza, że ​​właściwość celowo ma mieć „jeszcze brak wartości” podczas inicjalizacji.

Korzystając ze zmiennych opcjonalnych, pamiętaj, aby je rozpakować !, takimi jak:

self.window!.backgroundColor = UIColor.whiteColor();
akashivskyy
źródło
1
W Twojej odpowiedzi wszystko ma sens, aż do końca. czy możesz wyjaśnić tę ostatnią część? odwijać się? czy to jest wymagane?
DanMoore,
1
Nie możesz przechowywać w swoim pliku właściwości, która nie jest opcjonalna AppDelegate(chyba że ma ona wartość podczas inicjalizacji lub zostanie rozwiązana leniwie). Jeśli przechowujesz opcjonalną właściwość i masz pewność, że tak nie jest nil, „rozpakuj ją z jej opcjonalności” za pomocą !operatora.
akashivskyy
jaka jest najlepsza praktyka, self.window! lub używając if let window = ..?
śmiech
1
Jeśli jesteś pewien, że Twoje okno istnieje (i możesz być pewien w tym konkretnym przypadku), możesz przejść z !.
akashivskyy
więc czy to oznacza, że ​​kiedy używamy scenorysów, to w jakiś sposób domyślny kolor backgroundColor .white?
Miód
91

Wszystko, czego potrzeba, aby nie używać scenorysów do rootViewController:

1 · Zmień AppDelegate.swiftna:

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 · Utwórz ViewControllerpodklasę UIViewController:

import UIKit

class ViewController: UIViewController {

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

3 · Jeśli utworzyłeś projekt z szablonu Xcode:

  1. Usuń parę klucz-wartość dla klucza "Main storyboard file base name" z Info.plist.
  2. Usuń plik storyboardu Main.storyboard .

Jak widać w pierwszym fragmencie kodu, zamiast niejawnie rozpakowywać opcjonalne, wolę if letskładnię rozpakowywania opcjonalnej windowwłaściwości. Tutaj używam go if let a = a { }tak, aby opcjonalne astało się nieopcjonalnym odniesieniem wewnątrzif nieopcjonalnym -statement o tej samej nazwie - a.

Wreszcie self.nie jest konieczne, gdy odwołujemy się do windowwłaściwości wewnątrz własnej klasy.

tobiasdm
źródło
1
Dlaczego if let window = window {? Rozgryzłem to! Dzięki temu nie musisz go używać za window!każdym razem.
Bilal Akil
@ 2unco Cieszę się, że to rozgryzłeś. Jest to opisane w ostatniej części mojej odpowiedzi na temat if let a = a {}.
tobiasdm
Chciałbym przenieść wezwanie do makeKeyAndVisible()bycia po ustawieniu rootViewController. W przeciwnym razie otrzymasz ostrzeżenie o tym, jak oczekuje się, że okno będzie miało główny kontroler widoku pod koniec uruchamiania aplikacji.
Sebastien Martin
if let a = a { }wygląda dziwnie. Czy na pewno można użyć tej samej nazwy zmiennej dla nieopcjonalnego odwołania? Apple zawsze używa różnych nazw w swoich dokumentach Swift. Dlaczego jest to lepsze niż zwykłe używanie za window!każdym razem?
ma11hew28
1. if let a = a { }jest całkowicie w porządku. Możesz użyć, if let anA = a { }jeśli poczujesz się bardziej komfortowo. 2. window!jest sprawdzaniem w czasie wykonywania, ponieważ jawnie rozpakowujesz opcjonalny. Podoba mi się sprawdzanie czasu kompilacji, które zapewnia nam Swift, więc dlaczego go nie użyć.
tobiasdm
13

Jeśli chcesz zainicjować swój viewController za pomocą xib i i potrzebujesz użyć kontrolera nawigacji. Oto fragment kodu.

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
}
Wilkołak
źródło
6

Wypróbuj następujący kod:

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
źródło
2

Znalazłem odpowiedź, że nie ma to nic wspólnego z konfiguracją xcode, usunięcie scenorysu i odniesienia z projektu jest właściwe. Miało to związek z szybką składnią.

Kod jest następujący:

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
źródło
Ale po co odpowiadać na własne pytanie, skoro rozwiązaniem jest inna odpowiedź?
akashivskyy
strona nie była aktualizowana i nie widziałem odpowiedzi, dopiero po wysłaniu
EhTd
2

Możesz to zrobić w ten sposób:

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
źródło
Czy var window: UIWindow? określić, że jest to właściwość opcjonalna?
Sean Dunford
Po prostu próbowałem dodać drugi delegat var w aplikacji bez niego i stwierdziłem, że moje powyższe stwierdzenie jest prawdą.
Sean Dunford
2

Zalecam użycie kontrolera i XIB

MyViewController.swift i MyViewController.xib

(Możesz utworzyć za pomocą File-> New-> File-> Cocoa Touch Class i ustawić „także utwórz plik XIB” true, podklasę UIViewController)

class MyViewController: UIViewController {
   .....    
}

i AppDelegate.swift func applicationnapisz następujący kod

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

Powinno pracować!

Yi Feng Xie
źródło
Próbowałem w ten sam sposób, o którym wspomniałeś, ale błąd: Zamykanie aplikacji z powodu nieprzechwyconego wyjątku „NSInternalInconsistencyException”, powód: „Nie można załadować NIB w pakiecie:
shripad20
2

Zaktualizowano dla Swift 3.0:

window = UIWindow()
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
Tiago Martinho
źródło
2

Aktualizacja: Swift 5 i iOS 13:

  1. Utwórz aplikację z pojedynczym widokiem.
  2. Usuń Main.storyboard (kliknij prawym przyciskiem myszy i usuń).
  3. Usuń nazwę scenorysu z domyślnej konfiguracji sceny w Info.plistpliku:wprowadź opis obrazu tutaj
  4. Otwórz SceneDelegate.swifti zmień func scenez:
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 }
}

do

 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
źródło
1

Oto przykład pełnego szybkiego testu dla kontrolera 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
źródło
0

Dlaczego po prostu nie utworzysz pustej aplikacji? scenorys nie jest dla mnie stworzony ...

allemattio
źródło
0

Możemy stworzyć aplikację nawigacyjną bez scenorysu w Xcode 6 (iOS 8) w następujący sposób:

  • Utwórz pustą aplikację, wybierając język projektu jako Swift.

  • Dodaj nowe pliki klas dotykowych cocoa z interfejsem xib. (np. TestViewController)

  • W szybkim mamy tylko jeden plik wchodzący w interakcję z xib, tj. Plik * .swift, nie ma plików .h i .m.

  • Sterowanie xib możemy połączyć z plikiem swift takim samym, jak w iOS 7.

Poniżej znajduje się kilka fragmentów do pracy z kontrolkami i 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()
    }

}

Zmiany w pliku 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) {
    }

}

Znajdź przykład kodu i inne informacje na http://ashishkakkad.wordpress.com/2014/06/16/create-a-application-in-xcode-6-ios-8-without-storyborard-in-swift-language-and -praca-z-sterowaniem /

Ashish Kakkad
źródło
0

W systemie iOS 13 i nowszych podczas tworzenia nowego projektu bez scenorysu użyj poniższych kroków:

  1. Utwórz projekt za pomocą Xcode 11 lub nowszego

  2. Usuń końcówkę i klasę scenorysu

  3. Dodaj nowy plik za pomocą xib

  4. Należy ustawić widok główny jako UINavigationController SceneDelegate

  5. dodaj poniżej kod func scene (_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {// Użyj tej metody, aby opcjonalnie skonfigurować i dołączyć UIWindow windowdo podanego UIWindowScene scene. // Jeśli używasz scenorysu, windowwłaściwość zostanie automatycznie zainicjowana i dołączona do sceny. // Ten delegat nie oznacza, że ​​łącząca scena lub sesja są nowe (patrzapplication:configurationForConnectingSceneSession zamiast tego). // straż niech _ = (scena jako? UIWindowScene) else {return}

    jeśli niech windowScene = scena jako? UIWindowScene {self.window = UIWindow (windowScene: windowScene) let mainController = HomeViewController () as HomeViewController let navigationController = UINavigationController (rootViewController: mainController) self.window! .RootViewController = navigationContrible.

Półka Yogesh
źródło