Как мне создать новый проект Swift без использования раскадровок?

107

Создание нового проекта в XCode 6 не позволяет отключить раскадровки. Вы можете выбрать только Swift или Objective-C и использовать или нет Core Data.

Я попытался удалить раскадровку и из проекта удалить основную раскадровку и вручную установить окно из didFinishLaunching

В AppDelegate у меня есть это:

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

Однако XCode выдает ошибку:

Класс AppDelegate не имеет инициализаторов

Кому-нибудь это удалось?

EhTd
источник

Ответы:

71

Вы должны пометить windowи testNavigationControllerпеременные как опция:

var window : UIWindow?
var testNavigationController : UINavigationController?

Классы Swift требуют инициализации необязательных свойств во время создания экземпляра:

Классы и структуры должны установить для всех своих сохраненных свойств соответствующее начальное значение к моменту создания экземпляра этого класса или структуры. Сохраненные свойства нельзя оставлять в неопределенном состоянии.

Свойства необязательного типа автоматически инициализируются значением nil, что указывает на то, что свойство намеренно предназначено для того, чтобы «еще не иметь значения» во время инициализации.

При использовании необязательных переменных не забудьте развернуть их !, например:

self.window!.backgroundColor = UIColor.whiteColor();
Акашевский
источник
1
В вашем ответе все имеет смысл до конца. не могли бы вы объяснить последнюю часть ?? развернуть? это требуется?
DanMoore
1
Вы не можете сохранить необязательное свойство в своем AppDelegate(если оно не имеет значения во время инициализации или не разрешается лениво). Если вы сохраняете необязательное свойство и уверены, что это не так nil, вы «разворачиваете его из его необязательности» с помощью !оператора.
akashivskyy
какова лучшая практика, self.window! или используя if let window = ..?
Смеющийся человек
1
Если вы уверены, что ваше окно существует (и вы можете быть уверены в этом конкретном случае), вы можете пойти с !.
akashivskyy
Значит ли это, что когда мы используем раскадровки, backgroundColor каким-то образом установлен по умолчанию .white?
Дорогая,
91

Все, что нужно, чтобы не использовать Раскадровки для rootViewController:

1 · Изменить AppDelegate.swiftна:

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 · Создайте ViewControllerподкласс UIViewController:

import UIKit

class ViewController: UIViewController {

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

3 · Если вы создали проект из шаблона Xcode:

  1. Удалите пару ключ-значение для ключа "Main storyboard file base name"из Info.plist.
  2. Удалите файл раскадровки Main.storyboard.

Как видно из первого фрагмента кода, вместо неявного разворачивания if letнеобязательного windowсвойства мне больше нравится синтаксис разворачивания необязательного свойства. Здесь я использую его if let a = a { }так, чтобы необязательный параметр aстал необязательной ссылкой внутри ifоператора с тем же именем - a.

Наконец, в self.этом нет необходимости при ссылке на windowсвойство внутри собственного класса.

Tobiasdm
источник
1
Почему if let window = window {? Я понял! Так что не нужно использовать window!каждый раз.
Билал Акил
@ 2unco Я рад, что ты это понял. Это описано в последней части моего ответа о if let a = a {}.
tobiasdm
Я бы переместил вызов, makeKeyAndVisible()чтобы быть после настройки rootViewController. В противном случае вы получите предупреждение о том, что в конце запуска приложения в окне должен быть корневой контроллер представления.
Себастьян Мартин
if let a = a { }выглядит странно. Вы уверены, что можно использовать то же имя переменной для необязательной ссылки? Apple всегда использует разные имена в своих документах Swift. Кроме того, почему это лучше, чем просто использовать window!каждый раз?
ma11hew28
1. if let a = a { }совершенно нормально. Можете использовать, if let anA = a { }если вам так удобнее. 2. window!Это проверка во время выполнения, поскольку вы явно разворачиваете необязательный. Мне нравятся проверки времени компиляции, которые предоставляет нам Swift, так почему бы не использовать его.
tobiasdm
13

Если вы хотите инициализировать свой viewController с помощью xib и вам необходимо использовать контроллер навигации. Вот фрагмент кода.

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
источник
6

Попробуйте следующий код:

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

}
ПРЕМКУМАР
источник
2

Я нашел ответ, который не имеет ничего общего с настройкой xcode, удаление раскадровки и ссылки из проекта - это правильно. Это было связано с быстрым синтаксисом.

Код следующий:

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
источник
Но зачем отвечать на свой вопрос, если решение в другом ответе?
akashivskyy 04
страница не обновлялась, и я не увидел ответа, только после публикации
EhTd 04
2

Вы можете сделать это так:

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
источник
Есть ли var window: UIWindow? указать, что это необязательное свойство?
Шон Данфорд
Я просто попытался добавить вторую переменную в делегат приложения без нее и обнаружил, что мое приведенное выше утверждение верно.
Шон Данфорд
2

Я рекомендую вам использовать контроллер и xib

MyViewController.swift и MyViewController.xib

(Вы можете создать через File-> New-> File-> Cocoa Touch Class и установить "также создать файл XIB" true, подкласс UIViewController)

class MyViewController: UIViewController {
   .....    
}

и AppDelegate.swift func applicationнапишите следующий код

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

Надо работать!

И Фэн Се
источник
Я пробовал так же, как вы упомянули, но с ошибкой: завершение работы приложения из-за неперехваченного исключения «NSInternalInconsistencyException», причина: «Не удалось загрузить NIB в комплекте:
shripad20
2

Обновлено для Swift 3.0:

window = UIWindow()
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
Тьяго Мартиньо
источник
2

Обновление: Swift 5 и iOS 13:

  1. Создайте приложение с одним представлением.
  2. Удалите Main.storyboard (щелкните правой кнопкой мыши и удалите).
  3. Удалите имя раскадровки из конфигурации сцены по умолчанию в Info.plistфайле:введите описание изображения здесь
  4. Открыть SceneDelegate.swiftи изменить func sceneс:
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 }
}

к

 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()
    }
}
Джогендра Кумар
источник
1

Вот полный пример быстрого теста для 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
          }
    }
Коновалов Дмитрий
источник
0

Почему бы вам просто не создать пустое приложение? раскадровка не создана для меня ...

Allemattio
источник
0

Мы можем создать приложение на основе навигации без раскадровки в Xcode 6 (iOS 8) следующим образом:

  • Создайте пустое приложение, выбрав язык проекта Swift.

  • Добавьте новые файлы классов касания какао с помощью интерфейса xib. (например, TestViewController)

  • В swift у нас есть только один файл, взаимодействующий с файлом xib, т.е. * .swift, файлов .h и .m нет.

  • Мы можем связать элементы управления xib с быстрым файлом так же, как в iOS 7.

Ниже приведены некоторые фрагменты для работы с элементами управления и 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()
    }

}

Изменения в файле 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) {
    }

}

Найдите образец кода и другую информацию на http://ashishkakkad.wordpress.com/2014/06/16/create-a-application-in-xcode-6-ios-8-without-storyborard-in-swift-language-and -работа-с-элементами управления /

Ашиш Каккад
источник
0

В iOS 13 и выше при создании нового проекта без раскадровки используйте следующие шаги:

  1. Создать проект с использованием Xcode 11 или выше

  2. Удалить перо раскадровки и класс

  3. Добавить новый файл с помощью xib

  4. Необходимо установить корневое представление как UINavigationController SceneDelegate

  5. добавьте ниже код сцены func (_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {// Используйте этот метод, чтобы при необходимости настроить и прикрепить UIWindow windowк предоставленному UIWindowScene scene. // При использовании раскадровки windowсвойство будет автоматически инициализировано и прикреплено к сцене. // Этот делегат не подразумевает, что сцена или сеанс подключения являются новыми (см. application:configurationForConnectingSceneSessionВместо этого). // охранник let _ = (сцена как? UIWindowScene) else {return}

    если пусть windowScene = сцена как? UIWindowScene {self.window = UIWindow (windowScene: windowScene) let mainController = HomeViewController () как HomeViewController let navigationController = UINavigationController (rootViewController: mainController) self.window! .RootViewController = navigationController self.window}.

Йогеш шелке
источник