个性化阅读
专注于IT技术分析

iOS和OSX的Swift 2.0简介

本文概述

本文于2016年2月更新, 以反映Swift 2.0中的更改

Swift是Apple用于为本机iOS应用程序编程的新语言选项。它是对Objective-C的补充, 而且这种情况将持续一段时间, 现在是版本2, 没有比这更好的时间来学习新语言了。

Objective-C开发人员会发现许多与其他功能的相似之处, 例如类型推断, 强类型输入, 不依赖头文件, 泛型等等。

在本教程中, 我将向你展示如何开始使用Swift 2开发iOS应用程序。我将向你展示如何设置开发环境, 研究语言基础以及将语法与Objective-C, JavaScript和C#进行比较。在本教程的最后, 你将使用Swift创建一个简单但完整的iOS应用程序。

在许多情况下, Objective-C, C#和Swift共享相似的语法, 请参考此文件以获取完整参考。

设置环境

与Objective-C一样, Swift需要最新的Mac和Xcode。在撰写本文时, 最新版本的Xcode 7.2是从Mac App Store下载的。

获取Xcode

该文件下载量很大, 大约为2.5 GB, 因此可能需要一段时间。下载完成后, 打开“应用程序”目录并启动Xcode。安装升级时所需的任何其他组件。如果你安装了以前版本的Xcode, 它将更新为最新版本。

现在你可以开始使用Swift进行探索和开发了。

语言基础和语法

让我们看一下语言语法, 与Objective-C的区别以及它与其他现代语言的比较。

由于无法在本教程中深入介绍Swift的所有方面, 因此我将使用简单的示例来展示高级概念。

如果你想继续, 请打开Xcode, 选择“游乐场入门”, 然后键入每个示例以查看运行情况。

欢迎使用Xcode

你可以从GitHub下载我们将尝试使用的代码以快速参考。

变量和常量

要在Swift中声明变量, 请使用关键字var:

var number = 1

用其他语言:

目标C

int number = 1;

C#

var number = 1;

Java脚本

var number = 1;

你可以看到Swift语法有多么相似, 唯一的区别是声明的末尾缺少分号。

与Objective-C的主要区别在于, 你不必定义变量类型, 因为Swift使用类型推断, 并且能够理解变量由于其初始值而为数字。

你可以根据需要定义类型:

var number: Int = 1

让我们在Swift中声明一个字符串变量:

var language = "Swift"

在这里, Swift中的声明看起来更加简洁, 几乎与C#和JavaScript相同。与Objective-C相比如何?

NSString *language = @"Swift";

使用Swift, 不需要使用内存指针(*)或在字符串值前加上@符号。

如果你使用的是Foundation框架, 则无论如何使用NSString都可以使用Swift字符串, 并且可以访问整个NSString API

Swift中的常量可以使用let关键字声明:

let language = "swift"

要么

let language: String = "Swift"

在其他语言中, 相同的声明如下所示:

目标C

NSString  *const language = @"Swift";

C#

const string language = Swift";

使用Swift可以在声明常量时进行类型推断。

在Swift中使用变量与其他语言没有什么不同, 但是它有一个简单的方法可以让你在字符串中添加值:

var designers = 4
var developers = 4

var teamSize = "The team has \(designers + developers) members"

数组

在Swift中, 你可以使用方括号[]创建数组和字典, 并通过在这些括号中编写索引或键来访问它们的元素。

var arr = ["first" , "second"]

在其他语言中, 相同的声明如下所示:

目标C

NSArray *arr = @[@"first", @"second"];

C#

var arr = new[] { "first", "second" };

的JavaScript

var arr = ["first" , "second"];

你可以使用索引值访问数组中的项目:

var order = arr[0]

并使用以下值设置值:

arr[0] = "zero"

该代码在Javascript和C#中是相同的, 但语句末尾使用分号。

目标C

NSString *order = arr[0];

你可以使用for item循环枚举数组:

for item in arr {
    // do something
}

在其他语言中, 相同的声明如下所示:

目标C

for(NSString *item in arr)
{
    // do something
}

C#

foreach (var item in arr) {
    // do something
}

的JavaScript

for (index = 0; index < order.length; ++index) {
     //do something
}

要将另一个项目添加到数组, 请使用+ =运算符:

arr += ["fourth"]

或附加函数:

arr.append("fifth")

辞典

通过定义键值对在Swift中声明字典。声明一个空字典时, 你必须定义键的类型和值。

var dict = Dictionary<String, String>()

你可以声明和分配值:

var dict = ["MEL": "Melbourne", "SYD": "Sydney"]

在其他语言中, 相同的声明如下所示:

目标C

NSDictionary *dict = @{
    @"MEL" : @"Melbourne", @"SYD" : @"Sydney"
};

C#

var dict = new Dictionary<string, string>
{
    { "MEL", "Melbourne" }, { "SYD", "Sydney" }
};

要从词典中访问项目, 请使用:

var entry = dict["MEL"]

在其他语言中, 相同的声明如下所示:

目标C

NSString *entry = dict[@"MEL"];

C#

var entry = dict["MEL"];

要将项目设置或添加到词典中, 请使用:

dict["PER"] = "Perth"

在其他语言中, 相同的声明如下所示:

目标C

dict[@"PER"] = @"Perth"

C#

dict["PER"] = "Perth";

要遍历字典, 请使用:

for (cityCode, cityName) in dict {
    print("\(cityCode) : \(cityName)")
}

cityCode变量将包含键, cityName变量将包含值。

在其他语言中, 相同的声明如下所示:

目标C

for (id key in dict) {
    NSLog(@"key: %@, value: %@", key, dict[key]);
}

C#

foreach(var item in dict) {
    var cityCode = item.Key;
    var cityName = item.Value;
}

循环

你已经了解了如何创建项目, 让我们看一下如何遍历它们。

首先, for循环语法:

for var number = 1; number < 5; number++ {
    //do something
}

如预期的那样, 你指定一个值并递增直到满足条件。 Objective-C和C#语法几乎相同, JavaScript也几乎相同, 但是省略了变量类型。

你可以使用Swift for in变体来获得相同的结果:

for number in 1...5{
    //do something
}

Swift创建数字变量并在迭代指定值时自动分配一个值。 1…5是一个封闭范围, 包括从1到5的数字。

使用先前创建的数组, 你可以使用此语法在数组中的城市上进行迭代。

for city in arr {
  print(city)
}

Swift提供了一段时间重复循环, 其语法几乎与Objective-C, C#和JavaScript相同:

while number < 10
{
    print(number)
    number++
}

while语句之后的变量是布尔值, 并且代码在评估为true时将执行。

重复循环的行为相同, 但是可以确保代码在评估条件之前至少执行一次。

var number  = 9
repeat {
   print(number)
   number++
}
while number<10

此示例确保在使用while语句对数字值进行增值和评估之前, 先显示该数字值。

有条件的

循环控制代码中的重复任务, 而if和switch语句控制流程。

Swift中的if语法可以带括号, 但是是可选的, 因此你可以使用任何喜欢的样式。

if city == "MEL" {
   print("Melbourne")
}

要么

if (city == "MEL") {
    print("Melbourne")
}

if语句后可以跟一个else if或else。

if city == "MEL" {
    print("Melbourne")
} else if city == "SYD" {
    print("Sydney")
} else {
    print("Perth")
}

Swift中的Switch语句后面要进行大小写验证, 但是因为没有隐式的穿通, 所以不需要break语句。这意味着一旦案例评估为真并执行, 下一个案例将不会评估。但是, 需要执行默认操作。

switch city {
    case "MEL":
        print("Melbourne")
    case "SYD":
        print("Sydney")
    default:
        print("Perth")
}

case语句可以包含多个用逗号或范围分隔的值。使用Swift, 你可以在switch语句中使用NSString, 而Objective-C则不可能。

功能

函数是一个涉及较大的主题, 但是基础知识很有用, 因此你可以声明和使用它们。

在Swift中使用关键字func声明一个函数:

func sayName() {
  print("Patrick")
}

通过指定变量名称和类型, 在括号内传递参数。

func sayName(name: String) {
  print(name)
}

你可以传递以逗号分隔的多个参数。

func sayName(name: String, lastName: String) {
  print("\(name) \(lastname)")
}

通过在参数后添加->并指定返回类型来声明返回结果的函数。

func createName(name: String, lastName: String) -> String {
   return "\(name) \(lastname)"
}

使用Swift创建iOS应用程序

学习新的编程语言最好通过编写代码和创建应用程序来实现。因此, 让我们使用Swift创建一个简单的iOS应用程序。

该应用程序将连接到TheMovieDB API, 请求即将上映的电影的列表, 下载JSON结果, 将其解析为Dictionary和Arrays, 然后将此数据填充到Table View中。

为了使本教程保持简单, 它将涵盖一些常见任务, 例如创建UI元素并将其与代码连接, 使用多个控制器, 委托和协议, 并展示如何使用Swift进行异步操作, 这是该语言的优势所在。

开始之前, 请从themoviedb.org网站注册并请求应用程序API密钥。如果你还没有帐户, 请注册, 打开你的帐户页面, 并在API部分中生成一个新密钥。

该应用程序的最终代码在GitHub上, 并且我已经为每个阶段创建了分支。

让我们开始吧。

打开Xcode, 创建一个新项目, 在iOS部分中选择一个视图应用程序, 然后单击下一步。

单视图应用

我将我的项目命名为UpcomingMovies, 然后选择Swift作为语言。

新应用程序

单击下一步, 然后选择保存项目的位置。

现在, 通过选择Xcode中的Main.storyboard文件并从对象库中拖动一个表视图对象, 来创建一个表来显示应用程序数据。

插入表格

要访问代码中的表, 你需要创建一个委托, 一个数据源和一个出口。

选择情节提要文件, 按住控制键, 然后单击并从“表视图”拖动到“视图控制器”, 然后在弹出菜单中选择数据源。重复该过程, 然后选择委托选项。

要创建出口, 请选择视图->助手编辑器->显示助手编辑器菜单项。你将看到一个新部分, 其中显示了ViewControler.Swift文件中的代码。

选择表和这次的保持控件, 然后单击并从“表视图”拖动到代码窗口, 在类声明下释放。

给Outlet起一个名字, 我使用了appTableView, 然后单击connect。

创建一个Outlet

完成UI剩下的最后一项任务是。这是为了创建一个原型单元格, 该单元格将包含影片详细信息文本, 并将重新用于表中创建的每个单元格。

为此, 选择“表视图”, 然后在属性检查器中, 将原型单元格的数量更改为1。然后单击该单元格, 将“样式”更改为“字幕”, 并为其指定MovieResultsCell的标识符。

创建原型
更改字幕

好了, 是时候与Swift一起玩了。

首先, 你必须配置故事板前面连接的数据源和数据集。

在ViewController.swift中, 更改该类:

class ViewController: UIViewController {

对此:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

现在, 通过创建所需的方法来实现上面添加的2个新协议。

将以下代码行添加到ViewController.swift文件。

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1;
    }

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cellIdentifier: String = "MovieResultsCell"

        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: cellIdentifier)

        cell.textLabel?.text = "Test"
        cell.detailTextLabel?.text = "Test details"

        return cell
    }

第一种方法定义表中的行数, 第二种方法显示数据。

你可以删除以下代码, 因为它是不必要的。

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

ViewController.Swift代码应如下所示:

第一阶段代码概述

这样就完成了第1阶段, 继续并运行该项目, 你应该看到以下结果。

到目前为止创建的应用示例

现在该连接到我们的API并检索结果了。该代码应通用且可重复使用。目的是传递URL作为参数, 获取结果, 解析JSON并返回包含数据的数组。

然后, 可以将该代码重新用于后续对其他URL的API调用。

右键单击导航窗格中包含ViewController.swift的文件夹, 然后选择“新建文件”, 以创建一个新类。

创建一个新文件

选择Cocoa Touch Class, 单击Next并为其赋予一个有意义的名称, 我使用了APIController。保留以下默认选项。

创建API类

打开文件, 然后在import UIKit行下输入以下代码。

protocol APIControllerDelegate {
    func apiSucceededWithResults(results: NSArray)
    func apiFailedWithError(error: String)
}

这定义了一个协议, 该协议将在ViewControler.swift中实现, 并在API调用完成后接收结果。

让我们添加将进行实际调用并处理结果的函数。

在类的简化中, 添加以下代码:

var delegate:APIControllerDelegate?

  func getAPIResults(urlString:String) {

      //The Url that will be called.
      let url = NSURL(string: urlString)
      //Create a request.
      let request = NSMutableURLRequest(URL:url!)
      //Sending Asynchronous request using NSURLSession.
      NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
          do {
              //Check that we have received data
              guard let data = data else {
                  self.delegate?.apiFailedWithError("ERROR: no data")
                  return
              }
              //Call the JSON serialisation method to generate array of results.
              self.generateResults(data)
          }
          }.resume()
  }

func generateResults(apiData: NSData)
    {
        do {
            //Serialise the api data into a json object
            let jsonResult = try NSJSONSerialization.JSONObjectWithData(apiData, options: .AllowFragments)
            //verify we can serialise the json object into a dictionary
            guard let jsonDictionary: NSDictionary = jsonResult as? NSDictionary else {
                self.delegate?.apiFailedWithError("ERROR: conversion from JSON failed")
                return
            }
            //Create an array of results
            let results: NSArray = jsonDictionary["results"] as! NSArray
            //Use the completion handler to pass the results
            self.delegate?.apiSucceededWithResults(results)
        }
        catch {
            self.delegate?.apiFailedWithError("ERROR: conversion from JSON failed")
        }
    }

第一个函数采用URL, 并发出请求以从API接收数据。如果有错误, 它将执行传递错误字符串的协议的apiFailedwithError函数。成功时, 它将调用generateResults函数来解析API数据。

APIController类现在应如下所示。

APIController

这样就完成了第2阶段, 如果你构建并运行该项目, 你会发现这没有什么改变。

现在该填充表中的数据了。打开ViewController.Swift并将APIControler委托添加到Class中:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, APIControllerDelegate {

在appTable出口下方, 添加以下两行:

var searchResultsData: NSArray = []
  var api: APIController = APIController()

第一个变量将包含表数据。第二个变量创建用于调用其任何方法的API控制器的实例。

现在, 通过在现有tableView的下面添加以下函数来实现API控制器协议。确保用你自己的空API密钥替换。

  // MARK: APIControllerDelegate

  //Make the API call
  func getUpcomingMovies()
  {
      //Construct the API URL that you want to call
      let APIkey: String = "" //Replace with your Api Key"
      let APIBaseUrl: String = "https://api.themoviedb.org/3/movie/upcoming?api_key="
      let urlString:String = "\(APIBaseUrl)" + "\(APIkey)"

      //Call the API by using the delegate and passing the API url
      self.api.delegate = self
      api.getAPIResults(urlString)
  }

  //Handle the Error
  func apiFailedWithError(error: String) {
      let alertController = UIAlertController(title: "Error", message:
          error, preferredStyle: UIAlertControllerStyle.Alert)
      alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))

      self.presentViewController(alertController, animated: true, completion: nil)
  }
  //Handle the returned data
  func apiSucceededWithResults(results: NSArray) {
      self.searchResultsData = results
      self.appTableView.reloadData()
  }

现在, ViewController.swift应该看起来像这样。

VCwith代表

让我们更改tableView函数, 并将API数据映射到行和单元格。

替换以下代码

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cellIdentifier: String = "MovieResultsCell"   
      let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: cellIdentifier)

      cell.textLabel?.text = "Test"
      cell.detailTextLabel?.text = "Test details"

      return cell
  }

有了这个:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let cellIdentifier: String = "MovieResultsCell"

      let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier)! as UITableViewCell

      //Create a variable that will contain the result data array item for each row
      let cellData: NSDictionary = self.searchResultsData[indexPath.row] as! NSDictionary
      //Assign and display the Title field
      cell.textLabel!.text = cellData["title"] as? String

      // Construct the posterUrl to get an image URL for the movie thumbnail
      let imgURL: NSURL = getPoster(cellData["poster_path"] as? String)
      // Download an NSData representation of the image at the URL
      let imgData: NSData = NSData(contentsOfURL: imgURL)!
      cell.imageView!.image = UIImage(data: imgData)

      // Get the release date string for display in the subtitle
      let releaseDate: String = cellData["release_date"]as! String

      cell.detailTextLabel!.text = releaseDate

      return cell
  }

在此, 将API的值分配给每个单元格, 以获取电影标题, 海报和发行日期。

API并不总是返回海报的图像。这应该通过APIController中的JSON序列化来处理, 但是这种方法太复杂了, 无法在此进行介绍。因此, 出于此应用的目的, 让我们使用以下功能:

func getPoster(posterPath: String?) ->NSURL
    {
        guard let posterPath = posterPath, let baseUrl: String = "http://image.tmdb.org/t/p/w300", let urlString: String = "\(baseUrl)" + "\(posterPath)", let imgURL: NSURL = NSURL(string: urlString)
        else {
            let defaultImageUrl: NSURL = NSURL(string: "https://assets.tmdb.org/images/logos/var_8_0_tmdb-logo-2_Bree.png")!
            return defaultImageUrl
        }
        return imgURL
    }

这将检查是否从API返回了图像路径以及为该表构​​造的URL。否则, 将显示tmdb徽标。

替换以下功能

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1;
    }

带有:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return searchResultsData.count
    }

这将在表中创建与API结果一样多的行。现在表格单元已准备好接收数据, 是时候进行API调用了。

将以下行添加到viewDidLoad方法中

getUpcomingMovies()

现在, 完整的ViewController类应如下所示。

VC完成

在应用程序运行之前, 你需要启用“非HTTPS连接的应用程序传输安全性”, 因为tmdb API不提供加密的数据。

右键单击info.plist文件, 然后选择“打开为源代码”。

在此处输入图片说明

在文件的底部, 关闭词典标记之前, 添加以下代码。

  <key>NSAppTransportSecurity</key>
  <dict>
      <key>NSAllowsArbitraryLoads</key><true/>
  </dict>
介绍列表

就这样, 现在运行该应用程序, 它将显示所有即将上映的电影。

最终应用

希望你喜欢通过Apple的新语言进行的“快速”浏览, 并欢迎你在下面提出意见和问题。如果你想了解更多信息, 那么我建议你使用SitePoint的Hello World教程和Swift视频系列。

赞(0)
未经允许不得转载:srcmini » iOS和OSX的Swift 2.0简介

评论 抢沙发

评论前必须登录!