Swift以其新面目闪亮登场,北京iOS培训蓝鸥3G学院和您一起解析苹果新语言:

       
      Swift是一门集C语言、Objective-C语言优势于一身的全新编程语言,是由苹果开发的专门针对iOS以及OS X平台的程序设计语言,并且完全兼容C语言。Swift采用更安全的编程模式,并且添加了一些流行的特性,这让编程变得更加简单,更加灵活,更有乐趣。Swift以其全新的面貌展示给众人,借助于成熟的、非常受欢迎的Cocoa以及Cocoa Touch框架为重新定义软件开发方式创造了有利条件。

       Swift已经酝酿多年,苹果通过改进现有的编译器、调试器、以及基础框架为Swift建立了坚实的基础。我们通过自动引用计数技术(ARC)进一步简化了内存管理的方式。建立在Foundation框架以及Cocoa框架等坚实的基础上的框架,Swift已经具备现代化和标准化的特征。Objective-C已经演化到支持块语句(block)、集合字面量、模块以及通过使用框架来与现代化语言技术实现无缝对接。感谢这些基础工作,我们现在可以正式介绍苹果未来软件开发的全新语言-Swift。

      Swift对于使用Objective-C作为开发语言的开发人员来说可谓似曾相识,十分亲切。因为它采用Objective-C见名知意的参数命名规则以及强大的Objective-C动态对象模型。它可以与现有的Cocoa框架无缝对接,并且可以与Objective-C实现代码混编。建立在这些共同点上,Swift还引入了许多新特性、代码混编并且是完全面向对象的语言。

      Swift对于开发者来说是友好的。它是第一款像脚本语言一样灵活、有趣的企业级系统编程语言。它支持playgrounds模式,一个无需通过编译和运行程序就能允许开发者一边写Swift代码一边立即查看代码的执行结果的创造性尝试。

       Swift结合了开发语言的各种优势,这源自于苹果的优良的开发文化。其编译器为性能而生,而其语言为开发而生,缺一不可。这一切使得Swift成为开发者乃至苹果最有价值的投资。

      编写iOS和OS X应用,Swift是一个非常棒的方式,未来会持续引入新特性和新功能。对于Swift,我们拥有雄心壮志,真是迫不及待的想要看到您如何用它来创造奇迹。

Swift概览

      依照传统,第一次使用新的语言做开发,应当在屏幕上打印出来“Hello,world”。用Swift,只需要简单的写下如下语句:

 
println("Hello, world")


       如果你已经写过C语言或者Objective-C代码,Swift这种语法规则你一定会觉得很面熟,并且这已经是一个完整的程序了。你无需引入单独的类库来完成输入/输入或者字符串操作功能。代码书写在一个程序的全局入口,所以你不再需要main函数。最最重要的是你也不必在每行语句结束时写上恼人的分号。


       本章节将提供足够的信息帮助你如何使用Swift语言完成多种不同的编程工作。还不理解?不必担心,概览中提到的知识点将在本书随后的内容中会详细讲解。


    注:为了得到更好的体验,请在XCode中创建playground项目,Playgrounds可以编写Swift代码,同时 立即查看代码的执行结果


简单值

      使用let关键字声明常量,使用var关键字声明变量。虽然编译时不必知道常量的值,但是至少得为声明的常量赋值一次。这意味着声明一个常量,可以多次使用该常量对应的值。

var myVariable = 42

myVariable 50

let myConstant = 42

      常量或者变量应当与你所赋的值类型相同。通常,不用书写确切的类型。只需要为一个常量或者变量赋值,让编译器去推断它们的类型吧。在上述的例子中,编译器会推断出myVariable变量是一个整型integer因为其初值就是整型的。


      如果初值没有足够的信息用于推断其类型(或者根本没有初值)可以通过在常量或者变量名后添加冒号和类型名来指定其类型。

let implicitInteger = 70

let implicitDouble = 70.0

let explicitDoubleDouble = 70

实验:

      声明一个常量赋初值为4,并且指明其类型为Float型

      在Swift中不能隐式转换一个值的类型,如果需要将某个值转换成不同类型,需要创建代转类型的实例。

let label "The width is "

let width = 94

let widthLabel = label + String(width)

实验:

      尝试移除最后一行字符串转换函数,看到了什么错误?

     其实有更简单的方式将一些基本数据包含到字符串中,那就是将数据写在小括号中,然后在小括号前加一个反斜杠就可以了。例如:

let apples = 3

let oranges = 5

let appleSummary = "I have \(applesapples."

let fruitSummary = "I have \(apples + oranges)pieces of fruit."

实验:

      使用\()将一个浮点型数值加入到一个包含某人姓名的字符串中

      用中括号([ ])来声明数组和字典,然后通过在[ ]中写上数组的下标或者字典中的键来访问数据元素。

var shoppingList = ["catfish""water""tulips""blue paint"]

shoppingList[1] = "bottle of water"

 

var occupations = [

    "Malcolm": "Captain",

    "Kaylee": "Mechanic",

]

occupations["Jayne"] = "Public Relations"

 

     如果要创建空的数组或者字典,可以使用初始化语法。

let emptyArray = String[]()

let emptyDictionary = Dictionary<String, Float>()

      如果类型可以被编译器推断出来,那么你可以直接用[ ]创建空数组,[ : ]来创建字典—例如,当你为一个变量赋一个新值,或者为一个函数传参数是,你可以这样做:

shoppingList = []   // Went shopping and bought everything.


控制流程

      使用if和switch做条件判断,使用for-in,for,while和do-while来执行循环。值得注意的是,判断条件或者循环变量旁的小括号不是必写的。但是大括号依然要写。

let individualScores = [75431038712]

var teamScore 0

for score in individualScores {

    if score > 50 {

        teamScore += 3

else {

        teamScore += 1

    }

}

teamScore

      在if语句中,判断条件必须是布尔表达式(Boolean)—这样的话,if score{…}这句就是有错误的,因为score并不是隐式的跟0做比较。


      在当某些值可能为空的时候,你可以同时使用if和let,这样这些值就表示为可选的。一个可选的值既可以包含某个确定的值也可以为nil,nil表示一个空值。当然在类型后加一个问号(?)就可以将该值标记为可选的。

var optionalStringString? = "Hello"

optionalString == nil

 

var optionalNameString? = "John Appleseed"

var greeting = "Hello!"

if let name = optionalName {

    greeting = "Hello, \(name)"

}

实验:

      将optionalName赋值为nil,greeting的结果会是什么呢?当optionalName为nil是添加一个else语句来设置一个不同的greeting


      如果可选值为nil,那么if语句的判断条件就是false,大括号中的代码也会被跳过。否则,可选值就会执行相关的代码块并把结果赋值给let后面对应的常量,这样大括号所表示的代码块的值就会可用。


      不同于C语言或者Objective-C,switch语句在Swift语言中支持任意数据类型和各种各样的比较操作—并局限于整型和等式比较。

let vegetable = "red pepper"

switch vegetable {

case "celery":

   let vegetableComment = "Add some raisins and make ants on a log."

case "cucumber""watercress":

    let vegetableComment = "That would make a good tea sandwich."

case let x where x.hasSuffix("pepper"):

    let vegetableComment = "Is it a spicy \(x)?"

default:

 let vegetableComment = "Everything tastes good in soup."

}

实验:

      尝试移除default case,你看到了什么错误?

       当符合条件的case被执行后,程序将会跳出switch语句。程序并不会顺序执行接下来的case,所以在switch语句中就没有必要显式的通过在每个case对应的代码片段结尾使用关键字break来跳出该语句。


      同时,你可以通过两个变量来表示字典的每一个键值对再配合使用for-in来快速遍历字典。

let interestingNumbers = [

    "Prime": [23571113],

    "Fibonacci": [112358],

    "Square": [1491625],

]

var largest = 0

for (kindnumbersin interestingNumbers {

    for number in numbers {

        if number > largest {

    largest = number

}

largest

实验:

       通过添加一个新的变量来记录遍历得到的数中的最大数

        while语句依然继承自C语言,除非条件发生改变,否则会循环执行某段代码。同时循环的条件也可以写在最后面,这样可以确保循环至少会被执行一次—do-while。

var n = 2

while n < 100 {

    n = n * 2

}

n

 

var m = 2

do {

    m = m * 2

while m 100

m

        在for循环中,你可以使用..来描述循环变量的取值范围,或者依然使用C语言中声明变量,条件和自增运算的方式,这两者是等价的。

var firstForLoop = 0

for in 0..3 {

    firstForLoop += i

}

firstForLoop

 

var secondForLoop 0

for var i = 0i < 3; ++i {

secondForLoop += 1

}

secondForLoop

     如果是使用..的话,取值范围不包括上限(类似于i<5),若要包括则需要使用…(i<=5)


函数与闭包

      函数的声明需要使用关键字func。可以通过函数名和对应的参数列表来调用函数。通过使用->为函数指定返回值类型,便于区分参数名和参数类型。 

func greet(nameStringdayString) -> String {

    return "Hello \(name), today is \(day)."

}

greet("Bob""Tuesday")

 

实验:

       ***参数day,为greet函数添加一个新的参数来表示中午吃什么饭

       使用元组来为函数制定多个返回值

func getGasPrices() -> (Double, Double, Double) {

    return (3.593.693.79)

}

getGasPrices()

      函数的参数数量也可以是可变的,可以用一个数组来表示。 

func sumOf(numbersInt...) -> Int {

    var sum = 0

    for number in numbers {

        sum += number

    }

    return sum

}

sumOf()

sumOf(4259712)

实验:

      定义一个可以计算所有参数平均值的函数


      值得注意的是,Swift语言总函数是可以嵌套的,被嵌套的函数可以访问外层函数中定义的变量。对于太长或者太复杂的函数,你可以以函数嵌套的方式来重构该函数。

func returnFifteen() -> Int {

    var y = 10

    func add() {

        y += 5

    }

    add()

    return y

}

returnFifteen()

      Swift中函数有一些特别的优点:

       一个函数可以作为另外一个函数的返回值使用。

func makeIncrementer() -> (Int -> Int) {

    func addOne(numberInt) -> Int {

        return 1 + number

    }

    return addOne

}

var increment makeIncrementer()

increment(7)

     一个函数也可以作为另一个函数的参数使用

func hasAnyMatches(list: Int[], conditionInt -> Bool) -> Bool {

    for item in list {

        if condition(item) {

            return true

        }

    }

    return false

}

func lessThanTen(numberInt) -> Bool {

turn number < 10

}

var numbers = [2019712]

hasAnyMatches(numberslessThanTen)

      函数实际上是一种特殊的闭包。你可以通过大括号({})来创建一个匿名闭包。然后通过使用in来分割参数并为包体返回类型。

numbers.map({

    (numberInt) -> Int in

    let result = 3 * number

    return result

})

实验:
重写闭包,如果的得到的是奇数,则返回0

        有多种创建闭包的简单方法。如果一个闭包的类型是已知的,例如作为代理的回到函数,你就可以忽略参数和返回值的类型。单一语句的闭包会把该语句的值作为返回值。

numbers.map({ number in 3 * number })

       你可以把数字当做参数名—这一点在短闭包中非常有用。当一个闭包被用作函数的最后一个参数时,它可以直接写在小括号里。

sort([153122]) { $0 > $1 }

类与对象
     
在创建一个类时,类名前需要加class关键字修饰。类中属性的声明与声明常量或者变量的方式一致。唯一区别就是属性的上下文是类。类中方法的声明也于函数的声明一致。

class Shape {

    var numberOfSides = 0

    func simpleDescription() -> String {

        return "A shape with \(numberOfSidessides."

    }

}

实验:

      使用let声明一个常量属性,再声明一个拥有参数的方法

      通过在类名后面加小括号的形式可以创建一个类的实例。通过点语法来访问实例的属性以及方法。

var shape = Shape()

shape.numberOfSides = 7

var shapeDescription =shape.simpleDescription()

      当前的Shape类少了一个非常重要的方法:创建该类实例时的初始化方法。可以使用init方法来创建。

class NamedShape {

    var numberOfSidesInt = 0

    var nameString

   

    init(nameString) {

        self.name = name

    }

           funcsimpleDescription() -> String {

  return "A shape with \(numberOfSidessides."

       }

}