Swift教程二: 如何创建一个简单的IOS应用

Tags: swift ios

欢迎回到我们的Swift系列教程!

Swift系列教程一中,我们了解了Swift语言的基础知识,并创建了自己的小费计算器类。

在这篇Swift教程中,我们将学习如何制作一个简单的IOS应用。具体而言,我们将为上一教程中开发的小费计算器类创建用户界面。

我写这篇教程的目标是使这篇教程适合IOS初学者以及计划过渡到Swift的具备iOS开发经验的开发者。

在这篇Swift教程中,您将需要Xcode(在写这篇Swift教程的时候是Xcode 6-Beta)的最新副本。你不需要具备Swift或Objective-C的开发经验,不过如果你有一些编程经验,那么对于学习这篇教程将会非常有帮助。

注:在写这篇教程的时候,由于Xcode6仍处于beta阶段所以我们不能发布的Xcode6的截图。因此,我们在这篇教程中没有贴出Swift的截图。

一、开始

启动Xcode中,并转到 File\New\Project,选择iOS\Application\Single View Application,然后单击下一步。

输入TipCalculator作为应用名称,将开发语言设置为Swift,目标设备设置为iPhone,请确认Use Core Data没有被选中。

然后单击下一步,选择一个目录来保存您的项目,然后单击创建。

让我们看看Xcode帮你创建了哪些东西。选择Xcode的左上角的iPhone 5 Simulator,然后点击play来测试您的应用。模拟器执行后,你应该可以在模拟器中看到一个空白屏幕,Xcode为你的应用程序创建了一个空白屏幕;

在本教程中,你会填满它!

二、创建你的模型(Model)

在为你的应用程序创建用户界面之前要做的第一件事情是:创建应用程序的模型(Model)。模型(Model)是一个类(或一组类)代表来表示数据和操作,你的应用程序将使用这些数据。

在本教程中,应用程序的模型就是在Swift教程一中创建的TipCalculator类,这篇教程中将被重命名为TipCalculatorModel。

让我们把这个类添加到项目中。选择 File\New\File 然后选择 iOS\Source\Swift File,将文件命名为 TipCalculatorModel.swift 然后单击Create。

注意:您不能从应用程序直接调用保存在playground中的代码。playground文件只是用于测试和原型设计;如果你想在应用程序中使用playground中的代码,必须像你刚才做的一行,把它移到一个Swift文件中。

打开TipCalculator.swift,从之前教程中赋值TipCalculator类并粘贴进去,然后进行以下更改:

    1. 重命名类为:TipCalculatorModel

    2. 将total和taxPct的申明更改为变量(因为用户使用时会改变这些值)

    3. 正因为如此,您需要更改subtotal属性为Computed Property。

将subtotal属性替换为下列内容:

var subtotal: Double {
  get {
    return total / (taxPct + 1)
  }
}

一个Computed Property并不实际存储值。它得值是基于其他值每次计算获得的。在这里,subtotal的值每次都是基于total和taxPct的当前值计算出来的。

注意:您也可以根据需要为Computed Property提供一个setter方法,参考下面语法:

var subtotal: Double {
  get {
    return total / (taxPct + 1)
  }
  set(newSubtotal) { 
     //... 
  }
}

你的setter方法将更新Computed Property背后的属性(即根据newSubtotal的值重新计算total和taxPct),但是对于我们要做的程序来说这是没有意义的,所以在这里我们不打算使用它。

    4.删除初始化函数init中subtotal的代码

    5.删除该文件中的所有注释

当你完成上述步骤,你的 TipCalculatorModel.swift 文件看起来是这样的:

import Foundation
 
class TipCalculatorModel {
 
  var total: Double
  var taxPct: Double
  var subtotal: Double {
    get {
      return total / (taxPct + 1)
    }
  }
 
  init(total:Double, taxPct:Double) {
    self.total = total
    self.taxPct = taxPct
  }
 
  func calcTipWithTipPct(tipPct:Double) -> Double {
    return subtotal * tipPct
  }
 
  func returnPossibleTips() -> [Int: Double] {
 
    let possibleTipsInferred = [0.15, 0.18, 0.20]
    let possibleTipsExplicit:[Double] = [0.15, 0.18, 0.20]
 
    var retval = [Int: Double]()
    for possibleTip in possibleTipsInferred {
      let intPct = Int(possibleTip*100)
      retval[intPct] = calcTipWithTipPct(possibleTip)
    }
    return retval
 
  }
}

嗯,你应用的Model完成了,现在是视图(View)的时间了。

三、Storyboard和Interface Builder

注意:如果你是一位经验丰富的iOS开发者,这一部分和下可以作为知识回顾。然而为了加快你学习的速度,你可能想直接跳过该章节阅读视图控制器之旅部分。那个章节为你准备了具备用户界面的起始应用。 

你将在StoryBoard中创建你的IOS应用的用户界面。Xcode中自带了一个叫做Interface Builder内置的工具,可以可视化的编辑你的StoryBoard。

使用 Interface Builder,你可以通过简单地拖放为你的应用程序(视图View)布局按钮(button)、文本(text field)、标签(label)和其他控件。

好了现在可以开始了,首先在Xcode的左侧点击Main.storyboard在Interface Builder中打开Storyboard。编辑窗口中有很多东西,所以让我们一段一段来看。

  1. 最左边的是Project Navigator,在那里你可以看到你项目中的所有文件。

  2. 在Interface Builder的左边是你的Document Outline(文档大纲),在那里你可以一目了然地看到你应用程序(视图控制器)中每个"屏幕(screen)"的所有视图(View)。请务必点击"down"箭头旁的每一个项目充分扩大Document Outline(文档大纲)的显示区域。(现在你的应用程序只有一个空白view在唯一的视图控制器中。你很快会往这里添加东西的)

  3. 在你的视图控制器左侧有一个箭头,表示控制器是初始视图控制器,或当应用程序启动时首先显示的视图控制器。您可以通过拖动箭头到不同的视图控制器,或在属性检查器(Attributes Inspector)中修改"Is Initial View Controller"属性为其他视图控制器来修改它。

  4. 在Interface Builder的底部,你会看到"w Any", "h Any"之类的信息。这代表你应用程序的布局当前可以适配任何屏幕尺寸,可以通过Auto Layout来实现这点。点击这个区域,您可以指定布局仅适合特定尺寸的设备。后续教程中我们会介绍Adaptive UI和Auto Layout。

  5. 在您的视图控制器的顶部,你会看到三个小图标,他们代表视图控制器本身和其他两个项目:Responder、Exit。如果你有Xcode的使用经验,你会发现这些图标的位置改变了(他们曾经在视图控制器下方)。在本教程中,你不会使用这些图标,所以现在可以不用管他们。

  6. 在Interface Builder的右下角是与 Auto Layout相关的四个图标。同样,我们会在后续教程中介绍他们。

  7. 在Interface Builder的右上角是Inspectors,您当前选择的时文档大纲视图。如果看不到Inspectors,可以用View\Utilities\Show Utilities打开它。
    Inspectors有一些选项卡,我们本教程中会使用其中一些选项卡,来配置项目中的视图。

  8. 在Interface Builder的右下角是Libraries。这里列出了很多不同类型的视图或视图控制器,可以在你的应用程序中使用。后面我们将会将会使用Libraries中的控件来布局应用程序。

四、创建视图

我们的TipCalculatorModel类有两个输入项:总计(total)和纳税百分比(tax percentage)。

我们需要让用户可以通过键入总数,所以需要一个文本字段(text field)。纳税百分比通常来说是值的范围,因此我们将使用一个滑块(slider)。此外,需要为滑块(slider)与文本字段(text field)配置相应的标签(label),还需要一个导航栏显示应用名称、一个按钮单击它执行小费计算以及一个文本字段(text field)来显示结果。

让我们开始一点点来构建用户界面。

  1. 导航栏(Navigation bar),通过选择视图然后使用Editor\Embed In\Navigation Controller来添加导航栏,而不是直接添加一个导航栏。这将在视图中添加一个导航栏。双击导航栏 (在视图内),并将文本设置为小费计算器。

  2. 标签(label),从对象库中将标签拖动到视图。双击标签并将其文本设置为Bill Total(Post-Tax): 选择的标签,在Inspector的第五个选项卡 (Size Inspector),设置X=33,Y=81。对另一个标签重复此操作,但将文本设置为Tax Percentage(0%):X=20,Y=120。

  3. 文本字段(Text Field),从对象库中将文本字段拖至视图。在属性检查器(Attributes Inspector)中设置Keyboard Type=Decimal Pad。在大小检查器(Size Inspector)中设置 X=192、 Y=72、 Width=268。

  4. 滑块(Slider),从对象库中将滑块拖到视图。在属性检查器(Attribute Inspector)中设置Minimum Value=0,Maximum Value=10 和 Current Value=6。在大小检查器中(Size Inspector)设置 X= 90、Y=111、Width=272。

  5. 按钮(Button),从对象库中将按钮拖到视图。双击该按钮,并将文本设置为Calculate。在大小检查器(Size Inspector)中设置 X=208 和 Y=149。

  6. 文本控件(Text View),从对象库中将文本控件拖动到视图中。双击文本并删除占位符文本。在属性检查器(Attributes Inspector)中,确保可编辑(Editable)和可选择(Selectable)这两个选项没有被选中。在大小检查器(Size Inspector)中设置 X=20,Y=187,Wdith=440 和 Height=288。

  7. 手势识别控件(Tap Gesture Recognizer),从对象库中拖动手势识别控件到主视图中。这样当用户点击视图时可以关闭已打开的键盘。

  8. 自动布局(Auto Layout),Interface Builder中最棒的功能是可以为应用自动建立合理的布局,当然在这个项目中它同样也可以做到。要做到这一点,点击Interface Builder的左下角中的第三个按钮,并选择Add Missing Constraints。

构建并在iPhone 5模拟器上运行,应该可以看到一个基本的用户界面了!

五、视图控制器(View Controller)之旅

注意: 如果你跳到这一节,这里到目前为止是该项目的 zip 文件

到目前为止,我们已经创建了应用程序的模型和视图 — — 现在时候开始编写视图控制器(view controller)了。打开 ViewController.swift,这是我们应用程序的单一视图控制器的Swift代码。它负责管理视图和模型之间的通信。

这个类已经具备以下的代码:

// 1
import UIKit
 
// 2
class ViewController: UIViewController {
 
  // 3
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
  }
 
  // 4
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
 
}

有一些Swift中新的元素我们还没有学到,让我们先大概介绍一下。

  1. iOS 被分成多个框架,每个框架包含不同的代码集。在应用程序使用框架前我们必须将其导入,就像这里看到的。UIKit框架包含视图控制器的基类以及各种控件,如按钮和文本字段。

  2. 这里是Swift中类继承的第一个历次,在这里,我们声明了UIViewController子类ViewController(注1)。

  3. 这个当视图控制器第一次被访问时由根视图调用。当你重写Swift的方法是你需要使用override关键字标记它。这是为了避免错误地重写方法的情况发生。

  4. 当设备运行时内存不足时,将调用此方法。这个方法是释放资源的好地方。

注1:对于经验丰富的iOS开发者 — — 注意你不需要想Objective-C一样定义类前缀以避免命名空间冲突(即你不需要这个RWTViewController 的名字)。这是因为Swift支持命名空间,我们在项目中创建的类具有自己的命名空间。

下面的示例有助于理解命名空间,将类声明替换为以下内容:

class UIViewController {
}
 
class ViewController: UIKit.UIViewController {

这里的UIKit.UIViewController指向UIKit命名空间中的UIViewController类。同样,TipCalculator.UIViewController就是指想我们项目中的UIViewController类。

六、连接视图(View)和视图控制器(View Controller)

现在,我们已经了解了视图控制器类,现在让我们添加一些属性到它的子视图,并在Interface Builder中连接他们。要做到这一点,在ViewController类中添加这些以下属性(viewDidLoad之前):

@IBOutlet var totalTextField : UITextField!
@IBOutlet var taxPctSlider : UISlider!
@IBOutlet var taxPctLabel : UILabel!
@IBOutlet var resultsTextView : UITextView!

这里我们声明了四个变量,参考第一篇教程 — — UITextField、 UISlider、 UILabel 和 UITextView。

但这里还是有两个不同的地方:

  • 这些变量的前缀有@IBOutlet关键字。Interface Builder会扫描代码寻找任何具有@IBOutlet的属性,同时会对外暴露所有被发现的属性,这些属性可以被连接到视图。

  • 变量被标记了一个感叹号(!)。这表明变量是隐式解析可选类型(implicitly unwrapped)。这种类型的意思是说在写代码时可以假定它们已被赋值,如果他们没有被赋值的话应用程序将会崩溃。隐式解析可选类型(Implicitly unwrapped optionals)的值会在使用时自动解析,所以没必要使用操作符!来解析它(比如使用在Storyboard中创建的用户界面元素)。

让我们尝试将这些属性连接到用户界面中的元素。

打开Main.storyboard并在文档大纲(Document Outline)中选择您的视图控制器。打开连接检查器(Connections Inspector,第6个选项卡),您将在Outlets部分中列出了你创建的所有属性。

你会发现在resultsTextView的右侧有一个小圆圈。按住Ctrl拖动那个圆圈到文本字段(Calculate按钮下方)下面然后释放来将Swift属性连接到视图控件上。

在另外三个属性上重复此操作,将他们连接到相应的 UI 元素。

注:还有另一个更容易的方式来视图控制器上连接属性和空间。

当您打开Main.storyboard时,你可以通过View\Assistant Editor\Show Assistant Edito打开编辑助理(Assistant Editor),并确保编辑助理设置为显示您的视图控制器的Swift代码。

然后,你可以按住Ctrl拖动控件到编辑助理(Assistant Editor)中viewDidLoad的前面,在弹出窗口输入一个名称来创建属性,并单击连接(Connect)。

这样只需要一个步骤就可以在视图控制器中创建该属性并将其连接到Interface Builder,很方便吧!

这两种方式;你可以任意选择你喜欢的。

七、连接视图控制器(View Controller)和动作(Action)

连接到我们将视图连接到视图控制器上的属性一样,你同样需要为视图连接特定的动作(如单击按钮)。

要做到这一点,打开ViewController.swift并在类中的任意位置添加下面三个新方法:

@IBAction func calculateTapped(sender : AnyObject) {
}
@IBAction func taxPercentageChanged(sender : AnyObject) {
}
@IBAction func viewTapped(sender : AnyObject) {
}

当你声明视图动作的回调函数时需要有相同的签名-- 一个没有返回值的函数,并且只有一个AnyObject类型的参数,AnyObject(和Objective-C中的id等价)表示任何类型的类。

为了让Interface Builde能发现新方法,你需要为这些方法添加@IBAction关键字(就像你标记为属性标记@IBOutlet关键字一样)。

接下来,切换回Main.storyboard并确保在文档大纲(Document Outline)中选择视图控制器。确保Connections Inspector已打开(第6个TAB),你会看Received Actions部分看到你的新方法。

找到calculateTapped右边的圆点,并拖动该圆点到Calculate按钮上。

在弹出窗口中选择Touch Up Inside。这个选项的意思是:“当用户在屏幕上按下按钮并释放时,调用方法calculateTapped”。现在,在另外两种方法上重复本操作:

  • 拖动taxPercentageChanged:到滑块(Slider)并将其连接到Value Changed动作这个动作当每个用户移动滑块时触发。

  • 拖动viewTapped:到文档大纲(Document Outline)的Tap Gesture Recognizer 上,没有手势识别没有动作(Action)可以选择;你的方法只会在手势被识别时触发调用。

注:跟属性一样,使用Interface Builder连接动作和方法同样有简单的方式捷。

您只需在Assistant Editor中按住Ctrl拖动需要连接动作的控件(如按钮)到Swift代码视图控制器中,在出现的弹出窗口中选择Action并且给方法起个名字即可。

这会在你的Swift文件中创建一个方法签名并且同时连接方法和操作。两种方式是一样的,你只需要使用你习惯的方式就好了!

八、连接视图控制器和模型

功能几乎已经完成了--现在要做的就是连接视图控制器(View Controller)和模型(Model)。

打开ViewController.swift并在类中为模型添加一个属性和一个用来刷新屏幕的方法:

let tipCalc = TipCalculatorModel(total: 33.25, taxPct: 0.06)
 
func refreshUI() {
  // 1
  totalTextField.text = String(format: "%0.2f", tipCalc.total)
  // 2
  taxPctSlider.value = Float(tipCalc.taxPct) * 100.0
  // 3
  taxPctLabel.text = "Tax Percentage (\(Int(taxPctSlider.value))%)"
  // 4
  resultsTextView.text = ""
}

我们来一行行的讲解refreshUI方法:

  1. 在Swift中转换类型时需要明确指定被转换的类型。在这里我们需要将tipCalc.total从Double转换为String。

  2. 我们想要将tax percentage(税收比率)显示为一个整数(如:0%-10%)而不是一个小数(如0.06)。所以在这里需要你乘以100。

    注:转换是必要的,因为taxPctSlider.value属性是一个浮点数。

  3. 在这里,你使用字符串插值来更新用来显示税收百分比(tax percentage)的标签(label)。

  4. 当用户点击计算按钮是清除结果。

下一步,在viewDidLoad方法底部增加refreshUI的调用:

refreshUI()

使用下面的代码实现taxPercentageChanged和viewTapped方法:

@IBAction func taxPercentageChanged(sender : AnyObject) {
  tipCalc.taxPct = Double(taxPctSlider.value) / 100.0
  refreshUI()
}
@IBAction func viewTapped(sender : AnyObject) {
  totalTextField.resignFirstResponder()
}

taxPercentageChanged是将taxPctSlider.value的值除以100;

当触摸视图时会调用viewTapped方法,该方法会调用totalTextField.resignFirstResponder方法。

使用以下代码实现calculateTapped方法:

@IBAction func calculateTapped(sender : AnyObject) {
  // 1
  tipCalc.total = Double((totalTextField.text as NSString).doubleValue)
  // 2
  let possibleTips = tipCalc.returnPossibleTips()
  var results = ""
  // 3
  for (tipPct, tipValue) in possibleTips {
    // 4
    results += "\(tipPct)%: \(tipValue)\n"
  }
  // 5
  resultsTextView.text = results
}

继续一行行解释上面的代码:

  1. 在这里,你需要将字符串转换为Double。这稍微有点麻烦,希望后续Swift会有更简单的方法。(注2)

  2. 这里在tipCalc模型上调用returnPossibleTips方法,它返回一个字典包含消费比率对应的可能的小费值。

  3. 这是在Swift中如何同时枚举字典的键和值的方法

  4. 在这里,使用字符串插值创建结果字符串将放在显示结果的文本域中(\n是换行符)。

  5. 最后,你用结果字符串设置的结果文本域。

注2:如果你想知道这是如何工作的。

在写这篇教程的时候,Swift的String类还不能访问每一个NSString的方法(的SString是Foundation框架的string类)。特别是,Swift的String类没有一个方法可以像NSString一样将字符串转换为Double。

可以通过(XXX as NSString)()将Swift字符串转换成一个NSString。这样就可以调用NSString的方法将字符串方法转换为double,当然NSString其他的方法同样也可用。

要了解更多的关于NSString的方法,可以看看NSString类参考

就是这样!构建和运行,享受你自己制作的小费计算器吧!

注:对于如何根据小费百分比对结果进行排序,请参考下面内容。
只需将3部分代码替换为以下for循环:

var keys = Array(possibleTips.keys)
sort(&keys)
for tipPct in keys {
  let tipValue = possibleTips[tipPct]!
  let prettyTipValue = String(format:"%.2f", tipValue)
  results += "\(tipPct)%: \(prettyTipValue)\n"
}

可以得到字典的键(在这里是小费百分比),但并没有任何顺秀,所以你必须使用内置的排序函数sort,sort默认使用<操作符(用数字顺序)。

一旦得到了已排序的键,那么可以根据键遍历字典并按照顺序用dictionary[key]方法将键-值放入新的字典。

版权归属于英文原文:http://www.raywenderlich.com/74904/swift-tutorial-part-2-simple-ios-app

翻译:www.4byte.cn



本文链接:http://www.4byte.cn/learning/120000/swift-jiao-cheng-er-ru-he-chuang-jian-yi-ge-jian-dan-de-ios-ying-yong.html