如何在Xcode中创建一个不带Storyboard的空应用程序。

148

Xcode6在创建新项目时删除了Empty Application模板。如何在Xcode6及以上的版本中创建一个无Storyboard的空应用程序,就像早期版本一样?


3
这是一篇非常好的教程,讲解了如何在Xcode 6中移除storyboard并创建有用的空项目。 - Anurag Bhakuni
阅读此链接:http://xcodenoobies.blogspot.my/2015/10/how-to-create-basic-single-view-project.html - GeneCode
最新的 iOS9 和 Xcode 7 教程:https://medium.com/frozen-fire-studios/start-your-xcode-project-without-a-storyboard-fb7009f43c8f - Ryan Poolos
15个回答

269

XCode6 及以上版本没有直接创建空应用程序选项,如同 XCode5 和以前的版本。但是我们仍然可以通过以下步骤创建一个不带 Storyboard 的应用程序:

  1. 创建一个 Single View Application
  2. 删除 Main.storyboardLaunchScreen.xib(选择它们,右键单击,并选择从项目中删除或完全删除)。
  3. Info.plist 文件中删除 "Main storyboard file base name" 和 "Launch screen interface file base name" 条目。
  4. 打开 AppDelegate.m 并编辑 applicationDidFinishLaunchingWithOptions 函数,使其看起来像这样:

Swift 3 及以上版本:

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

Swift 2.x:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
    {
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window?.backgroundColor = UIColor.whiteColor()
        self.window?.makeKeyAndVisible()
        return true
    }

Objective-C:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.window.rootViewController = [[ViewController alloc] init];
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    }

22
我喜欢保留 LaunchScreen.xib 文件和相应的 Info.plist 条目。没有它,应用在较大的iPhone上将不会占据整个屏幕大小,看起来很丑。 - tboyce12
2
我喜欢使用Storyboard。Storyboard用来创建各种内容非常方便,但是我需要在不依赖Storyboard的情况下进行初始设置。 - Mazyod
可能是Xcode 7中的一个bug,我无法从项目信息设置屏幕中完全删除Main.storyboard。我使用了@Silentwarrior提到的Xcode 5空应用程序模板。 - GoodSp33d
3
除非你手动安装一个根视图控制器,否则在 XCode7 中,这个答案会生成一个运行时错误:'NSInternalInconsistencyException',原因是:'Application windows are expected to have a root view controller at the end of application launch'。 - user755921
11
请在AppDelegate.m文件的didFinishLaunchingWithOptions方法下添加以下代码: self.window.rootViewController = [[ViewController alloc]init]; 否则您将会收到以下错误提示: 'Application windows are expected to have a root view controller at the end of application launch'. - Rizwan Ahmed
显示剩余5条评论

31
一种简单的方法是将 XCode 5 中的 Empty Application 模板复制到 XCode 的模板目录中。
您可以从此处下载 XCode 5Empty Application 模板,然后解压并复制到 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application 目录。
附注:此方法也适用于 Swift!
编辑: 如@harrisg在下面的评论中所建议的那样,您可以将上述提到的模板放置在 ~/Library/Developer/Xcode/Templates/Project Templates/iOS/Application/ 文件夹中,以便在 Xcode 更新后仍可用。 如果没有这个文件夹,则可能需要在 ~/Library/Developer/Xcode/ 中创建以下目录结构:Templates/Project Templates/iOS/Application/ 使用这种简单方法,我能够在 XCode 6 中创建一个 Empty Application。(如下图所示) Xcode Empty Application Template 希望这可以帮助到您!

谢谢。请注意,您需要在Xcode更新后更换此模板。 - elliotrock
1
如果您将其放入~/Library/Developer/Xcode/Templates/Project Templates/iOS/Application/中,它就不必在每次Xcode更新时被替换。 - harrisg
@harrisg 在 Yosemite 中找不到此目录。您能确认它是否存在吗?谢谢。 - S1LENT WARRIOR
1
这种方法适用于Xcode 7.1,但是会创建LaunchScreen.storyboard,有些人可能不想要。我最终使用了它,因为它不会干扰我手动创建的视图。 - bitsand
1
请记得将文件解压到目录中,仅复制是不够的。 - Balaban Mario

17

还有几个步骤需要完成:

  1. 添加前缀文件(如果需要)
  2. 添加默认启动图像,否则在iPhone 5上,应用程序大小将为320x480。

下面是完整的教程:

  1. 删除Main.storyboard文件
  2. 删除LaunchScreen.xib文件
  3. 从Info.plist中删除“Main storyboard file base name”属性
  4. 从Info.plist中删除“Launch screen interface file base name”属性
  5. 将“[app name]-Prefix.pch”文件添加到支持文件夹中,其中包含以下内容:

#import <Availability.h>

#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
  • 将"$SRCROOT/$PROJECT_NAME/[pch文件名]"添加到项目设置-> Build Settings -> Apple LLVM 6.0 - Language -> "Prefix Header"

  • 将"YES"添加到项目设置-> Build Settings -> Apple LLVM 6.0 - Language -> "Precompile Prefix Header"
  • 打��"Image.xcassets"并添加LaunchImage
  • 构建项目,然后会有一个关于缺少默认启动图像的警告,只需按下警告并选择添加默认值即可,这将添加"Default-568h@2x"。 或者 - 如果您想要使用"Images.xcassets"中的启动图片,请转到项目设置-> TARGETS -> General -> 在"Launch Images Source"中选择使用资源目录,它将创建一个新的资源目录,您可以选择要从现有目录中使用哪个作为资源目录。
  • 实现application:didFinishLaunchingWithOptions:方法:

  • self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    //Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    return YES;
    

    16

    Akhil的答案完全正确。对于我们使用Swift的人来说,代码应该是这样的:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window?.backgroundColor = UIColor.whiteColor()
        self.window?.makeKeyAndVisible()
        return true
    }
    

    15

    Xcode 9.3.1Swift 4

    1. 首先,您需要在项目导航器菜单中删除Main.storyboard
    2. 然后删除Info.plist中的行Main storyboard file base name
    3. 并且不要忘记在您的项目目标 - 常规 - 部署信息中删除单元格主界面(只需删除Main)。
    4. 完成上述步骤后,打开AppDelegate.swift文件,在函数didFinishLaunchingWithOptions中编写以下内容:

      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
          // Override point for customization after application launch.
      
          window = UIWindow(frame: UIScreen.main.bounds)
          window?.makeKeyAndVisible()
          window?.rootViewController = UINavigationController(rootViewController: ViewController())
      
          return true
      }
      

    Xcode 11.2.1Swift 5

    1. 首先,您需要在项目导航器菜单中删除Main.storyboard
    2. 然后,在Info.plist中删除Main storyboard file base name行。
    3. 不要忘记在Project Target - General - Deployment Info中删除单元格Main Interface(只需删除Main)。
    4. 这一步非常重要,它在Xcode和Swift的早期版本中没有。在Info.plist中转到:Application Scene ManifestScene ConfigurationApplication Session RoleItem 0,并在此处删除Storyboard.name行。
    5. 完成上述步骤后,进入SceneDelegate文件,并在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 windowScene = (scene as? UIWindowScene) else { return }
      
          window = UIWindow(frame: windowScene.coordinateSpace.bounds)
          window?.windowScene = windowScene
          window?.rootViewController = ViewController()
          window?.makeKeyAndVisible()
      }
      

    10

    更新:Swift 5 和 iOS 13:

    1. 创建一个 Single View Application(单视图应用)。
    2. 删除 Main.storyboard 文件(右键单击并删除)。
    3. 从 Info.plist 文件的默认场景配置中删除 "Storyboard Name" :enter image description here
    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()
        }
    }
    

    2
    你还需要从Info.plist中删除“Main storyboard file base name”,否则你会收到错误提示:“找不到名为'Main'的故事板”。 - Ziad Hilal

    9

    还有一步需要完成:

    1)在plist文件中删除Main storyboard文件的基础名称

    //AppDelegate.h
    
    
    @property (strong, nonatomic) UIViewController *viewController;
    @property (strong, nonatomic) UINavigationController *nav;
    
    //AppDelegate.m
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {`enter code here`
        // Override point for customization after application launch.
    
        CGRect screenBounds = [[UIScreen mainScreen] bounds];
    
        UIWindow *window = [[UIWindow alloc] initWithFrame:screenBounds];
    
    
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    
    
        self.viewController = [[UIViewController alloc] initWithNibName:@"ViewController" bundle:nil];
    
        self.nav = [[UINavigationController alloc] initWithRootViewController:self.viewController];
    
        [window setRootViewController:  self.nav];
    
        [window makeKeyAndVisible];
    
        [self setWindow:window];
    
        return YES;
    }
    

    2
    有一个边界问题,UIScreen.mainScreen().bounds 打印出来是 :(0.0,0.0,320.0,480.0)。为什么会这样? - Esqarrouth

    6

    我有原始的空应用程序模板,它在Xcode 6之前的版本中使用。我已经将其上传到这里

    你可以手动下载并将其粘贴到Xcode模板目录中,或者使用Xcode的软件包管理器Alcatraz进行安装。只需搜索Xcode Empty Application即可。


    5

    删除Main.storyboard文件

    可以直接删除此文件。

    更新ProjectName-Info.plist文件

    删去Main storyboard base file name键。

    创建nib文件并将其链接到项目的视图控制器

    1.创建一个nib文件(文件->新建->文件->视图)

    2.将File's Owner的类更新为项目的视图控制器名称

    3.将File's Ownerview插座与nib文件中的view对象链接起来

    更新应用程序委托

    1.导入项目的视图控制器头文件

    2.更新application:didFinishLaunchingWithOptions:方法:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        MyViewController *viewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
        self.window.rootViewController = viewController;
        [self.window makeKeyAndVisible];
        return YES;
    }
    

    5

    对于 Xcode 8Swift 3 只需删除.storyboard文件,它会自动从您的.plist中删除相应的引用,并在您的AppDelegate.swift中添加以下代码。

        let initialViewController = UIViewController()
        initialViewController.view.backgroundColor = .white
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = initialViewController
        window?.makeKeyAndVisible()
    
    你可以编写自己的自定义ViewCountroller,并在AppDelegate.swift中使用它作为self.window?.rootViewController,只需在上面的代码中将UIViewController替换为你自己的ViewController即可。

    1
    使用 Xcode 9.1 和 Swift 4,如果我只删除故事板文件而没有手动从 .plist 中删除相应的引用,则会出现“找不到名为 'Main' 的故事板”的错误。似乎我必须手动删除引用。 - peacetype

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接