如何在不使用情节提要的情况下创建新的Swift项目?


107

在XCode 6中创建一个新项目不允许禁用Storyboard。您只能选择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”没有初始化程序

有人成功吗?


Answers:


71

您必须将windowtestNavigationController变量标记为可选:

var window : UIWindow?
var testNavigationController : UINavigationController?

Swift类要求在实例化期间初始化非可选属性:

类和结构必须在创建该类或结构的实例时将其所有存储的属性设置为适当的初始值。存储的属性不能处于不确定状态。

可选类型的属性会自动使用nil值进行初始化,这表明该属性在初始化过程中故意有“无值”的含义。

使用可选变量时,请记住用来将它们解包!,例如:

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

1
一切都完美无缺,直到最后。您能解释一下最后一部分吗?打开?这是必需的吗?
DanMoore 2014年

1
您不能在您的属性中存储非可选属性AppDelegate(除非该属性在初始化期间具有值,或者被延迟解析)。如果您存储可选属性并且确定不是nil,则可以使用!operator将其“从可选属性中解包” 。
akashivskyy 2014年

最佳实践是什么?self.window!或使用if let window = ..?
laughingman

1
如果确定您的窗口存在(并且可以确定在这种特殊情况下),则可以使用!
akashivskyy 2015年

所以这意味着当我们使用情节提要时,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 { }以便aif-statement中具有相同名称的可选参数成为非可选引用a

最后,self.window在其自己的类中引用该属性时,则没有必要。


1
为什么if let window = window {呢?我想到了!这样一来,您不必window!每次都使用。
Bilal Akil 2014年

@ 2unco我很高兴您知道了。这是关于的答案的最后一部分if let a = a {}
tobiasdm

我会移至呼叫makeKeyAndVisible()设置rootViewController。否则,您将收到有关在应用程序启动结束时期望窗口如何具有根视图控制器的警告。
塞巴斯蒂安·马丁

if let a = a { }看起来很奇怪。您确定可以对非可选引用使用相同的变量名吗?苹果在他们的Swift文档中总是使用不同的名称。另外,为什么这比window!每次都使用更好?
ma11hew28

1. if let a = a { }很好。if let anA = a { }如果可以让您感觉更舒适,则可以使用。2. window!是运行时检查,因为您显式展开了可选的包装。我喜欢Swift提供给我们的编译时间检查,所以为什么不使用它。
tobiasdm 2015年

13

如果要使用xib初始化viewController并需要使用导航控制器。这是一段代码。

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
}

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
    }

}

但是,如果解决方案在另一个答案中,那么为什么还要回答自己的问题呢?
akashivskyy 2014年

该页面未更新,仅在发布后我才看到答案
EhTd 2014年

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

var window:UIWindow吗?指定它是一个可选属性?
肖恩·邓福德

好吧,我只是尝试在没有它的情况下在应用程序委托中添加第二个var,发现上述声明是正确的。
肖恩·邓福德2014年

2

我建议您使用控制器和Xib

MyViewController.swiftMyViewController.xib

(您可以通过File-> New-> File-> Cocoa Touch Class创建并设置“也创建XIB文件”为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 2014年


2

更新:Swift 5和iOS 13:

  1. 创建一个单视图应用程序。
  2. 删除Main.storyboard(右键单击并删除)。
  3. 从文件的默认场景配置中删除情节提要名称Info.plist在此处输入图片说明
  4. 打开SceneDelegate.swiftfunc 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

您为什么不创建一个空的应用程序?故事板不是我创建的...


0

我们可以在Xcode 6(iOS 8)中创建没有情节提要的基于导航的应用程序,如下所示:

  • 通过选择项目语言为Swift创建一个空的应用程序。

  • 使用界面xib添加新的可可触摸类文件。(例如,TestViewController)

  • 在swift中,只有一个文件与xib交互,即* .swift文件,没有.h和.m文件。

  • 我们可以使用与iOS 7中相同的swift文件连接xib的控件。

以下是与控件和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(_ scene:UIScene,willConnectTo会话:UISceneSession,选项connectionOptions:UIScene.ConnectionOptions){//使用此方法可以选择配置UIWindow并将其附加window到提供的UIWindowScene上scene。//如果使用情节提要,则该window属性将自动初始化并附加到场景。//此委托并不意味着连接场景或会话是新的(请参阅application:configurationForConnectingSceneSession)。//保护let _ =(场景为UIWindowScene),否则{return}

    如果让windowScene =场景为?UIWindowScene {self.window = UIWindow(windowScene:windowScene)let mainController = HomeViewController()as HomeViewController let navigationController = UINavigationController(rootViewController:mainController)self.window!.rootViewController = navigationController self.window!.makeKeyAndVisible()}}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.