使用Swift 2 Advanced iOS进行iOS开发


在本章中,我们将介绍一些先进的功能,如在我们的应用程序上创建多个视图,添加导航栏,添加表视图,在应用程序中存储数据,制作Web应用程序等。

请仔细阅读每个部分,因为本章包含开发应用程序时所需的大部分内容。

多视图控制器

在我们之前的应用程序中,我们只提供了一个视图/视图控制器。但是,我们的应用程序中可以有多个视图,我们可以独立执行任何视图。

因此,我们将从创建一个新项目开始; 该项目的名称有多个视图。与其他项目一样,该项目还有一个View Controller和一个用于该控制器的Swift文件。(您可以通过在Identity Inspector中选择视图并查看其属性来查看。)

以下屏幕截图显示了我们当前视图的样子 -

入口点

在右侧(Identity inspector),我们可以看到与视图控制器相关的类。左侧的箭头是入口点。这是我们的应用程序的第一个视图,它将在应用程序开始运行后显示。

添加第二个多视图控制器

要将其他视图控制器添加到我们的应用程序,我们将在对象库中搜索视图控制器。一旦找到它,我们将视图控制器拖到我们的main.stroryboard,就在任何其他视图之外。

第二个多视图控制器

这就是您的应用程序的外观。现在,我们添加了一个视图控制器,但现在我们还需要为新添加的视图创建一个视图控制器类。

右键单击您的项目→新文件→可可触摸类→将其 命名为任何名称,我们将其命名为“SecondViewController”。

这是为视图控制器创建类文件的方法。现在,返回“main.storyboard”,单击第二个视图控制器并查看其Identity Inspector。

类字段现在必须为空,因此单击该字段并开始键入您在上一步中添加的类名。如果出现,请单击“输入”。

第二视图控制器

我们现在已经创建了一个多视图控制器,并为该视图添加了控制器类文件。但是,如果您运行该应用程序,它将不会显示您的第二个视图。为什么?

因为我们还没有添加一个函数,它将把我们带到那个视图。简而言之,我们尚未向我们的应用程序添加导航。别担心; 我们将在下一节中介绍它。

添加导航到应用程序

从一个视图转换到另一个视图的过程称为 Segueing ,即通过在两个视图之间创建segue来完成。为此,在第一个视图控制器中添加一个按钮,并控制从它拖动到第二个视图。当您松开按钮时,您将看到一些选项,如下面的屏幕截图所示。

添加导航到应用程序

从Action Segue中选择Show选项。现在运行您的应用程序,您将看到单击按钮时,会出现第二个视图(要在第二个视图中更清楚地添加内容,以便您可以识别)。

但是,现在您无法回到第一个视图。为此,我们有 导航控制器

添加导航控制器

选择第一个视图控制器,在顶部栏中单击 编辑器→嵌入→导航控制器

编辑

现在,我们的应用程序应该如下面的截图。

截图

我们应该注意到,在视图顶部有一个浅灰色的行。现在,当我们运行应用程序时,我们可以看到视图顶部有一个导航栏。当我们点击按钮时,我们将转到第二个视图,在那里我们将看到该导航栏中的后退按钮。单击此按钮,我们将返回初始视图。

将标题和后退按钮添加到导航栏

要在导航栏中添加标题,请单击导航栏,然后查看其属性检查器。我们会在那里看到 -

标题后退按钮

  • 标题 - 这将是导航栏的标题,它出现在中心。

  • 提示 - 显示在标题栏的顶部,位于中心。

  • 后退按钮 - 您可以在此处修改 后退按钮 中显示的文本。

目前,通过视图的按钮位于我们的视图中,如果我们想要在屏幕上显示其他内容,则可能不适合。因此,我们将在导航栏中添加一个Bar Button项,它将带我们进入第二个视图。但是,为此我们应该首先删除我们添加的最后一个按钮。

添加条形按钮项

在对象库中搜索条形按钮项,然后将其拖放到导航栏的右侧。将其命名为 - “Next>”,控制从它拖动到第二个视图,选择Show,就像我们添加的最后一个按钮一样。

添加栏按钮

现在运行应用程序,它看起来更干净,更好。这就是我们现在要做的所有导航。在随后的章节中,我们将在需要时使用Swift代码修改导航栏。

表视图

表将数据显示为包含多行的单列列表,可以进一步划分为多个部分。表应该用于以干净和有效的方式呈现数据。

在本节中,我们将了解如何添加表视图,添加原型单元,为表视图添加数据源和委托,更改表的属性以及为表视图单元设置动态数据。

添加表视图

要添加表视图,我们将首先创建一个新项目并将其命名为 - “tableView”。然后,转到对象库并搜索Table View,我们将看到表视图,表视图控制器和许多其他选项。但是,我们应该选择表视图,将其拖动并添加到默认视图Controller。

表视图

添加原型单元格

拉伸表视图以覆盖整个视图,同时突出显示表视图。检查其属性检查器,有一个名为Prototype cells的字段,当前为0.我们应将其值更改为1,现在您的视图应如下所示

原型细胞

更改单元标识符

现在,在您的视图中,单击您的原型单元格(这有点棘手)。因此,在您的文档大纲中,单击视图控制器→视图→表视图→表格视图单元格,现在在其属性检查器中有一个名为标识符的列,单击该列并将其命名为“单元格”。请参阅以下屏幕截图以了解上述步骤。

表视图单元格

添加委托和数据源

为了使我们的表视图动态化,我们需要它们来加载动态数据。因此,我们需要一个委托和数据源。要创建表的委托和数据源,请控制从表视图拖动到视图控制器或视图控制器顶部的黄色按钮,如下面的屏幕截图所示。

委派数据源

当我们释放光标时,我们会看到两个选项,dataSource和delegate,逐个选择它们(当你选择任何一个选项时,弹出窗口将隐藏,你需要重复上面的步骤来添加第二个选项) 。现在应该看起来像 -

奥特莱斯

这就是我们现在用UI / Main.Storyboard做的所有事情。现在切换到“ViewController.swift”文件。将 UITableViewDelegate,UITableViewDataSource 添加到viewController.swift,如下所示

表视图委派视图数据源

但是,现在Xcode将在此行中显示错误。

Xcode错误

这是因为有几种方法我们需要使用 UITableView

要查看这些方法,请单击UITableViewDataSouce,然后复制前两个方法,使用“numberOfRowsInSection”,“cellForRowAtIndex”参数并将它们粘贴到ViewController.swift中,然后再放入viewDidLoad()。

从这两个方法中删除此行 @available(iOS 2.0,*) 并添加开始和结束括号“{}”。现在,该视图将如下所示 -

UITableView的

Xcode必须在两个函数中都显示错误。但是,请不要担心,因为我们没有添加这些函数的返回类型。

numberOfRowsInSection - 此函数定义我们的部分将包含的行数。 所以现在将此行添加到您的方法中。

return 1 //This will return only one row.

cellForRowAt - 此方法返回每个单元格的内容, indexPath 包含每个单元格的索引。我们将创建一个单元格,然后我们将为该单元格分配一些值,最后返回单元格。

现在,您的功能应如下所示 -

internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return 1;
}
internal func tableView(_ tableView: UITableView,
   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = UITableViewCell(style:
   UITableViewCellStyle.default, reuseIdentifier: "Cell")
   cell.textLabel?.text = "First Row"
   return cell
}

在第一行中,我们创建一个具有默认样式的单元格,而 reuseIdentifier 是我们制作的原型单元格的名称。

Cell.textLable?.text - 这定义应该显示为该单元格标题的文本。

最后,我们从那里返回一个单元格。现在尝试运行您的应用程序,它应如下所示 -

重用标识符

时间表应用程序

在这个应用程序中,我们将继续我们的最后一个项目,我们将创建一个应用程序,我们打印2(2 ... 10 ... .20)的表。

因此,要创建此应用程序,只需更改项目的视图控制器文件即可。

更改功能如下所示

internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return 10;
}
internal func tableView(_ tableView: UITableView,
   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")
}

现在,运行您的应用程序。它应该如下所示。

时间表应用程序

现在,由于我们已完成表格视图并制作了应用程序,因此这是我们要解决的快速挑战。

挑战

制作一个应用程序,我们打印用户输入的数字的计数表。

提示 - 接受输入,添加一个按钮,按下该按钮将加载该表并计算该数字。 这里我们还需要以下函数,它将重新加载表数据。

tableView.reloadData()

这对您来说是一个挑战,因为我们已经涵盖了有关此应用程序的所有主题,因此我们不会为此提供解决方案。

蛋定时器应用

在这个应用程序中,我们将使用 Timer()Class Constructor 的概念来管理时间。我们将为您提供概念和编码。您必须自己创建UI,因为我们已经在前面的章节中多次讨论过每个UI元素。(虽然我们会提供一些看起来很新的提示)。

您的最终应用布局应如下所示 -

蛋定时器应用

这个应用程序会发生什么?

  • 标题标签具有起始值210。

  • 点击播放按钮,值应每秒减少一次。

  • 点击暂停,价值应该只在那里停止。

  • 点击-10,值应减少10,减量应继续。

  • 点击+10,值应增加10,减量应继续。

  • 点击重置,值应为210。

  • 价值不应低于0。

概念

  • 我们将使用类Timer()→var timer = Timer()的变量。

  • 我们将为刚刚创建的这个计时器变量设置一个值。

    • timer = Timer.scheduledTimer(timeInterval:1,target:self,selector:#selector(ViewController.processTimer),userInfo:nil,repeats:true)

    • timeInterval - >是我们要使用的时间间隔,

    • target - >是应该受影响的视图控制器,

    • selector - >是将使用此计时器的函数名称,

    • userInfo - > null并重复,是的,我们想重复一遍这是真的。

定时器无效

要通过编程停止计时器,我们将添加 timer.invalidate() 函数。

我们使用过的元素 -

导航栏 - 在导航栏中,我们添加了三个项目。

  • 条形按钮项目,左侧​​一个,右侧一个。
  • 标题命名为 - “我们的蛋计时器”。

导航栏

工具栏 - 工具栏显示在应用程序屏幕的底部,其中包含用于执行与当前视图或其中内容相关的操作的按钮。

工具栏是半透明的,可能有背景色调。当人们不太可能需要它们时,它们经常隐藏起来。

我们在UI的底部添加了一个工具栏,其中有5个项目。

  • 三个Bar按钮项,名为-10,Reset和+10。
  • 两个灵活的空间:条形按钮项之间的灵活空间 -

工具栏

如何将图标添加到栏按钮项?

选择您的栏按钮项。单击栏按钮项,转到属性检查器,单击“选择项目”,然后从显示的“下拉列表”中选择项目。

栏按钮的图标

同样,为所有其他按钮选择项目并创建上面给出的UI。将标签添加到视图的中心并将其作为插座连接,将其命名为 - timeLeftLabel

启动计时器的操作

以下是启动计时器的程序。

@IBAction func startTimerButton(_ sender: Any) {
   if !timerActive {
      timerActive = true
      eggTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector:
      #selector(ViewController.processTimer), userInfo: nil, repeats: true)
   }
}

创建以下功能

func stopTimer() {
   timerActive = false
   eggTimer.invalidate()
}

停止功能的动作

以下是停止功能的程序。

@IBAction func pauseTimerButton(_ sender: Any) {
   stopTimer()
}

减去时间的行动

以下是减去时间的程序。

@IBAction func subtractTime(_ sender: Any) {
   if timeLeft > 10 {
      timeLeft = timeLeft - 10
      timeLeftLabel.text = String(timeLeft)
   }
}

重置时间的行动

以下是重置时间的程序。

@IBAction func resetTimer(_ sender: Any) {
   timeLeft = 210
   timeLeftLabel.text = String(timeLeft)
}

addTime的操作

以下是添加时间的程序。

@IBAction func addTime(_ sender: Any) {
   timeLeft = timeLeft + 10
   timeLeftLabel.text = String(timeLeft)
}

现在,viewController.swift看起来应该像 -

import UIKit
class ViewController: UIViewController {
   @IBOutlet weak var timeLeftLabel: UILabel!
   var eggTimer = Timer()  // Initialize the Timer class.
   var timerActive = false // Prevents multiple timers from firing.
   var timeLeft = 210  
   func stopTimer() {
      timerActive = false
      eggTimer.invalidate()
   }

   func processTimer() {
      if timeLeft <= 0 {
         stopTimer()
         return
      }     
      timeLeft = timeLeft - 1;
      timeLeftLabel.text = String(timeLeft)
   }

   @IBAction func startTimerButton(_ sender: Any) {
      if !timerActive {
         timerActive = true
         eggTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector:
         #selector(ViewController.processTimer), userInfo: nil, repeats: true)
      }
   }

   @IBAction func pauseTimerButton(_ sender: Any) {
      stopTimer()
   }

   @IBAction func subtractTime(_ sender: Any) {
      if timeLeft > 10 {
         timeLeft = timeLeft - 10
         timeLeftLabel.text = String(timeLeft)
      }
   }

   @IBAction func resetTimer(_ sender: Any) {
      timeLeft = 210
      timeLeftLabel.text = String(timeLeft)
   }

   @IBAction func addTime(_ sender: Any) {
      timeLeft = timeLeft + 10
      timeLeftLabel.text = String(timeLeft)
   }

   override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
   }  
   override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated
   }
}

这就是我们将在我们的应用程序中所做的一切,尝试运行应用程序,它应该运行正常。

在本地存储上存储数据

在本地存储上存储数据意味着使用本地设备的存储来存储与设备上的应用程序相关的数据。我们有两种方法将数据存储在本地存储上,即 NSUserDefaultCoreData

让我们详细了解它们。

NSUserDefaults的

NSUserDefaults用于存储小块数据,例如首选项,设置或单个值。要在我们的应用程序中使用UserDefaults,我们只需要通过我们的代码创建对nsuserDefaults的引用,如下所示。

let defaultValues = NSUserDefaults.standardUserDefaults()

要在UserDefaults中为数据设置值,我们可以使用以下代码 -

defaultValues.setObject("Simplified iOS", forKey: "nameKey")  
func setDouble(value: Double, forKey defaultName: String)
func setBool(value: Bool, forKey defaultName: String)
func setObject(value: AnyObject?, forKey defaultName: String)
func setURL(url: NSURL?, forKey defaultName: String)
func setInteger(value: Int, forKey defaultName: String)
func setFloat(value: Float, forKey defaultName: String)

要从NSUserDefaults获取值,我们可以使用以下代码。

func boolForKey(defaultName: String) -> Bool
func integerForKey(defaultName: String) -> Int
func floatForKey(defaultName: String) -> Float
func doubleForKey(defaultName: String) -> Double
func objectForKey(defaultName: String) -> AnyObject?
func URLForKey(defaultName: String) -> NSURL?

CoreData

CoreData是一个持久性框架,支持大型数据事务。CoreData允许您构建用于存储用户数据的关系实体属性模型。CoreData是一个框架,可以使用SQLite,二进制格式来存储数据。

要在我们的应用程序中使用CoreData,我们将从一个新项目开始,并确保在创建项目时选中“使用核心数据”。

使用核心数据登录 - 创建一个新项目,选择使用CoreData,如以下屏幕截图所示。

使用核心数据

继续,直到项目打开,现在我们看到项目的文件比以前的项目多。

核心数据

这个文件 CoreData_demo.xcdatamodeld 是我们的数据库,我们将在其中创建用户表并存储数据。

概念 - 关于CoreData的事情是,即使我们关闭应用程序,并在几个月后打开它,它仍然会存储我们存储的数据,我们将在下一个应用程序中看到它们。

现在我们将看到如何添加核心数据和检索核心数据。

添加核心数据 - 要添加CoreData,请单击CoreData_demo.xcdatamodeld文件,然后我们将看到实体为空。 单击添加实体按钮,它将添加一个实体,现在双击实体名称并将其重命名为您喜欢的任何内容。

添加实体

现在单击实体,我们可以看到属性字段为空。单击加号,然后重命名该实体。从下一个字段中选择实体的类型。

属性

我们在其中添加了一个实体和一个属性。现在,如果我们转到 AppDelegate.swift ,我们可以看到添加了两个新函数,因为我们选择了CoreData。添加的两个功能是

功能已添加

- 在继续之前在文件中导入CoreData。

将数据保存到Core Data - 要在CoreData中保存一些数据,我们需要创建AppDelegate Class的对象。

let appDelegate = UIApplication.shared.delegate as! AppDelegate

并且,一个上下文对象

let context = appDelegate.persistentContainer.viewContext

然后,我们需要创建一个实体对象,它将调用我们的实体 -

let newValue = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)

我们现在将设置我们创建的属性的值。

newValue.setValue(textField.text, forKey: "name")

我们将使用保存数据

context.save();

从核心数据中 获取 - 在获取时,上述两个步骤(创建appDelegate和上下文)将是相同的。然后,我们将创建一个获取请求。

let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")

我们将创建一个对象来存储结果。

let results = try context.fetch(request)

然后我们将根据我们的要求查看结果。我们将在下一个创建的应用程序中看到更多的CoreData。

挑战 - 尝试创建一个应用程序,用户输入名称,然后单击登录并关闭应用程序。 当用户下次打开应用程序时,他应该仍然登录。然后添加一个按钮 - 注销,如果他点击该按钮,应用程序将再次询问用户名。

使用CoreData登录/注销

创建一个名为“Login”的视图项目,选择使用CoreData。单击CoreData_demo.xcdatamodeld并添加名为“Users”的实体。在其中,添加一个名为“name”的属性。

转到main.storyboard,添加文本字段和登录按钮。在其下方,添加标签,双击它并删除其内容。然后,添加一个注销按钮,转到其属性检查器并使'alpha'等于0.现在,我们的视图应如下所示

查看控制器场景

现在,转到视图控制器文件,打开助理编辑器并在UI元素和控制器文件之间创建连接。

注意 - 我们还将为这两个按钮创建插座,因为我们需要修改这些按钮的外观。 例如 - 当用户登录时,我们将隐藏登录按钮,如果用户未登录,我们将显示登录并隐藏登出按钮。

正如我们已经讨论过从CoreData添加和获取数据,我们将把代码放在这里。

Try-Catch - 您会注意到我们在代码中多次使用try-catch块。 这是因为如果我们不使用try- catch块并且程序中存在一些异常或错误,则执行将停止。然而,如果我们使用try catch块并且如果发生某些错误,则catch块处理错误。在我们的Swift教程中阅读更多相关内容.

登录/退出应用程序代码

让我们了解用于登录/注销应用程序的不同组件和代码。

登录按钮操作 - 以下代码说明了如何添加登录按钮操作。

var isLoggedIn = false
@IBAction func logIn(_ sender: AnyObject) {
   let appDelegate = UIApplication.shared.delegate as! AppDelegate
   let context = appDelegate.persistentContainer.viewContext
   if isLoggedIn {
      let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
      do {
         let results = try context.fetch(request)
         if results.count > 0 {
            for result in results as! [NSManagedObject] {
               result.setValue(textField.text, forKey: "name")
               do {
                  try context.save()
               }
               catch {
                  print("Update username failed")
               }
            }
            label.text = "Hi " + textField.text! + "!"
         }
      }
      catch {
         print("Update failed")
      }
   } else {
      let newValue = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
      newValue.setValue(textField.text, forKey: "name")
      do {
         try context.save()
         logInButton.setTitle("Update username", for: [])
         label.alpha = 1
         label.text = "Hi " + textField.text! + "!"
         isLoggedIn = true
         logOutButton.alpha = 1
      }  
      catch {
         print("Failed to save")
      }     
   }
}

注销按钮操作 - 以下代码说明如何添加注销按钮操作。

@IBAction func logOut(_ sender: AnyObject) {
   let appDelegate = UIApplication.shared.delegate as! AppDelegate
   let context = appDelegate.persistentContainer.viewContext
   let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
   do {
      let results = try context.fetch(request)
      if results.count > 0 {
         for result in results as! [NSManagedObject] {
            context.delete(result)
            do {
               try context.save()
            } catch {
               print("Individual delete failed")
            }
         }
         label.alpha = 0
         logOutButton.alpha = 0
         logInButton.setTitle("Login", for: [])
         isLoggedIn = false
         textField.alpha = 1
      }
   } catch {
      print("Delete failed")
   }
}

ViewDidLoad() - 以下代码说明了如何使用ViewDidLoad()函数。

override func viewDidLoad() {
   super.viewDidLoad()
   // Do any additional setup after loading the view, typically from a nib.
   let appDelegate = UIApplication.shared.delegate as! AppDelegate
   let context = appDelegate.persistentContainer.viewContext
   let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
   request.returnsObjectsAsFaults = false
   do {
      let results = try context.fetch(request)
      for result in results as! [NSManagedObject] {
         if let username = result.value(forKey: "name") as? String {
            logInButton.setTitle("Update username", for: [])
            logOutButton.alpha = 1
            label.alpha = 1
            label.text = "Hi there " + username + "!"
         }     
      }

   } catch {
      print("Request failed")
   }
}

请记住,您必须为这两个按钮创建一个插座和一个动作。

现在,保存并运行该应用程序。登录,关闭应用程序并再次运行它。它应该如下所示。

出口

这就是我们对CoreData所做的一切。使用相同的概念,我们可以构建许多CoreData应用程序。

控制键盘

在本节中,我们将学习如何控制键盘行为。例如 - 当我们在输入一些文本后在文本字段外部单击时,键盘不会关闭。在这里,我们将了解如何控制键盘。

单击输入字段外部时,键盘应消失

这是一个简单的任务,要做到这一点,只需将以下代码粘贴到viewController文件中,然后再关闭花括号。

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
   self.view.endEditing(true)  
}

通过执行此操作,它将使键盘在输入字段外部单击时消失。

返回键时,键盘应消失

为了使键盘消失,我们应该为视图控制器添加一个新类型。我们还将添加一个文本字段并创建名为textField的插座。最后,我们将添加 UITextFieldDelegate

UITextFieldDelegate

我们还将 控制+ 从输入字段 拖动 到视图控制器,并从显示的选项中选择委托。

然后,我们将添加以下功能。

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
   textField.resignFirstResponder()  
   return true
}

最终的View Controller文件应如下所示 -

import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
   override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
   }  
   override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated.
   }
   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      self.view.endEditing(true)
   }
   func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      textField.resignFirstResponder()
      return true
   }
}

下载网页内容 - 打开Facebook / Google

在本节中,我们将学习如何创建一个应用程序,它将分别按下每个按钮时打开Facebook和Google。我们还将学习Web视图和App传输层安全性的概念。在此之后,您将能够创建自己的浏览器。

- 我们需要在此应用程序中使用Internet连接。

制作Web应用程序

我们将制作一个新的单视图应用程序,iOS项目。在对象库的搜索栏中,我们将搜索Web视图,将其拖动并将其添加到main.Storyboard中的View控制器。

添加Web视图后,我们将其拉伸到所有角落。应用程序UI应如下所示 -

应用程序UI

我们将通过单击助理编辑器打开我们的main.storyboard并查看控制器。我们将为我们的webView和按钮创建一个插座。在加载时,应用程序将在webView中加载yahoo。在点击谷歌时,它应该加载谷歌,点击Facebook按钮,它应该加载Facebook页面。

最终视图应如下所示

最终观点

以下屏幕截图显示了我们的应用程序的不同屏幕应该如何。如果您尝试打开非https的Web服务,它将显示错误,我们将不得不在您的 info.plist 文件中添加App Transport Layer Security异常。

Infoplist