Swift 语言简介

简介

  1. 基于成熟的Cocoa 和 Cocoa Touch 框架
  2. 类脚本语言,又能满足工业标准
  3. 支持代码预览,易入门

基本语法

简单值

使用 let 来声明常量,使用 var 来声明变量

let a = 6  
let b:Int = 6  
let c:Int
c = 0  

值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。

 let label = "The width is"
 let width = 94  
 let widthLabel = label + String(width) 

使用方括号 [] 来创建数组和字典,并使用下标或者键(key)来访问元素。最后一个元素后面允许有个逗号。

var shoppingList = ["catfish", "water", "tulips", "blue paint"]   
shoppingList[1] = "bottle of water"  
var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]   
occupations["Jayne"] = "Public Relations"   

可以用 [] 和 [:] 来创建空数组和空字典——就像你声明变量或者给函数传参 数的时候一样。

shoppingList = []  
occupations = [:]  

如果你在需要使用 Bool 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。

let i = 1 if i {
// 这个例子不会通过编译,会报错 
}

元组

元组内的值可以是任意类型,并不要求是相同类型。

let http404Error = (404, "Not Found")
print("The status code is \(http404Error.0) message is \(http404Error.1)")

你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了

let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")

如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线( _ )标记

let (justTheStatusCode, _) = http404Error print("The status code is \(justTheStatusCode)")

你可以在定义元组的时候给单个元素命名

let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")

泛型

在尖括号里写一个名字来创建一个泛型函数或者类型。

func repeatItem(item: Item, numberOfTimes: Int) -> [Item] {
     var result = [Item]()
     for _ in 0..

你也可以创建泛型函数、方法、类、枚举和结构体。

enum OptionalValue {
case None
     case Some(Wrapped)
 }
 var possibleInteger: OptionalValue = .None
 possibleInteger = .Some(100)

运算符

Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。赋值符( = )不返回值,以 防止把想要判断相等运算符( == )的地方写成赋值符导致的错误,Swift 还提供了 C 语言没有的表达两数之间 的值的区间运算符( a..

  • 使用括弧来明确优先级、逻辑与(&&)或(||)非(!)比较运算(==、!=、>、 <、 >=、 <=)和其他语言用法相同

  • 与 C 语言和 Objective-C 不同,Swift 的赋值操作并不返回任何值。所以以下代码是错误的:

if x = y {
// 此句错误, 因为 x = y 并不返回任何值
}
  • 三目运算符 它的特殊在于它是有三个操作数的运算符,它的原型是 问题 ? 答案1 : 答案2 。它简洁地表达根据 问
    题 成立与否作出二选一的操作。如果 问题 成立,返回 答案1 的结果; 如果不成立,返回 答案2 的结果。
let contentHeight = 40
let hasHeader = true
var rowHeight = contentHeight
if hasHeader {
    rowHeight = rowHeight + 50
} else {
    rowHeight = rowHeight + 20
}
//等同于
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
  • 空合运算符 空合运算符(a??b)将对可选类型 进行空判断,如果 包含一个值就进行解封,否则就返回一个默认值 .这个运算符有两个条件:
    • 表达式必须是Optional类型
    • 默认值的类型必须要和存储值的类型保持一致
let defaultColorName = "red"
var userDefinedColorName: String? //默认值为 nil
var colorNameToUse = userDefinedColorName ??defaultColorName
// userDefinedColorName 的值为空,所以 colorNameToUse 的值为 "red"
  • 闭区间运算符 闭区间运算符( a...b )定义一个包含从 a 到 b (包括 a 和 b )的所有值的区间, b 必须大于等于 a 。 闭区 间运算符在迭代一个区间的所有值时是非常有用的,如在 for-in 循环中:
for index in 1...5 {
    print("\(index) * 5 = \(index * 5)")
}

控制流

条件操作

if
  1. 条件必须是一个布尔表达式——这意味着像 if score { ... } 这样的代码将报错,而不会隐形地 与 0 做对比。
  2. 可以一起使用 if 和 let 来处理值缺失的情况。这些值可由可选值来代表。一个可选的值是一个具体的值或者 是 nil 以表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。
var optionalName: String? = "John Appleseed"   
var greeting = "Hello!"  
if let name = optionalName {
    greeting = "Hello, \(name)"
} 
  1. 另一种处理可选值的方法是通过使用 ?? 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代 替。
let nickName: String? = nil   
let fullName: String = "John Appleseed"   
let informalGreeting = "Hi \(nickName ?? fullName)"
switch

支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。

let vegetable = "red pepper"  
switch vegetable {   
    case "celery":  
        print("Add some raisins and make ants on a log.")   
    case "cucumber", "watercress":
        print("That would make a good tea sandwich.")   
    case let x where x.hasSuffix("pepper"):   
        print("Is it a spicy \(x)?")   
    default:   
        print("Everything tastes good in soup.")   
}  

循环

for

可以在循环中使用 ..< 来表示范围,也可以使用传统的写法,两者是等价的。使用 ..< 创建的范围不包含上界,如果想包含的话需要使用 ... 。

 var secondForLoop = 0   
 for var i = 0; i < 4; ++i {
     secondForLoop += i
 }   
print(secondForLoop)  
   
   var firstForLoop = 0   
 for i in 0..<4 {
     firstForLoop += i
 }   
 print(firstForLoop) 

for in

可以使用 for-in 来遍历字典,需要两个变量来表示每个键值对。字典是一个无序的集合,所以他们的键和值以 任意顺序迭代结束。

let interestingNumbers = [
     "Prime": [2, 3, 5, 7, 11, 13],
     "Fibonacci": [1, 1, 2, 3, 5, 8],
     "Square": [1, 4, 9, 16, 25],
 ]  
 var largest = 0 
 for (kind, numbers) in interestingNumbers {
     for number in numbers {
         if number > largest {
             largest = number
         }
} }
print(largest)

while repeat

var n = 2
 while n < 100 {
n=n* 2 }
print(n)
 var m = 2
 repeat {
m=m* 2
} while m < 100
print(m)

函数和闭包

函数

  • 使用 func 来声明一个函数,使用名字和参数来调用函数。使用 -> 来指定函数返回值的类型。
func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet("Bob", day: "Tuesday")
  • 函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
}
return sum }
sumOf()
sumOf(42, 597, 12)
  • 函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。
func returnFifteen() -> Int {
     var y = 10
     func add() {
         y += 5
     }
     add()
     return y
 }
 returnFifteen()
  • 函数是第一等类型,这意味着函数可以作为另一个函数的返回值。
func makeIncrementer() -> (Int -> Int) {
     func addOne(number: Int) -> Int {
         return 1 + number
     }
     return addOne
 }
 var increment = makeIncrementer()
 increment(7)
  • 函数同样也可以作为参数传入另一个函数 。
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
     for item in list {
         if condition(item) {
             return true
} }
     return false
 }
 func lessThanTen(number: Int) -> Bool {
     return number < 10
 }
 var numbers = [20, 19, 7, 12]
 hasAnyMatches(numbers, condition: lessThanTen)
  • 多重返回值:你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回
func minMax(array: [Int]) -> (min: Int, max: Int) {
     var currentMin = array[0]
     var currentMax = array[0]
     for value in array[1.. currentMax {
             currentMax = value
} }
     return (currentMin, currentMax)
 }

可选元组返回,如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用可选的(Optional) 元组返回类型反映整个 元组可以是 nil 的事实。

func minMax(array: [Int]) -> (min: Int, max: Int)? {
     if array.isEmpty { return nil }
     var currentMin = array[0]
     var currentMax = array[0]
     for value in array[1.. currentMax {
             currentMax = value
         }
}
     return (currentMin, currentMax)
 }

  • 常量参数和变量参数,函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参
    数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使
    用。
func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
    let amountToPad = totalLength - string.characters.count
    if amountToPad < 1 {
        return string
    }
    let padString = String(pad)
    for _ in 1...amountToPad {
        string = padString + string
    }
    return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, totalLength: 10, pad: "-")
print(originalString)
  • 输入输出参数:变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些 修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数。定义一个输入输出参数时,在参数定义前加 inout 关键字。一个输入输出参数有传入函数的值,这个值被函数 修改,然后被传出函数,替换原来的值。
func swapTwoInts(inout a: Int, inout _ b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

输入输出参数不能有默认值,而且可变参数不能用 inout 标记。如果你用 标记一个参数,这个参数不能var被或者let标记。

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")

注意someInt和anotherInt在传入的时候前面都添加了&上面的 swapTwoInts 函数并没有定义任何返回值,但仍然修改了 someIn t 和 anotherInt 的值。输入输出参数是函数对函数体外产生影响的另一种方式。

  • 函数类型,每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。
func printHelloWorld() {
    print("hello, world")
}

这个函数的类型是: () -> void ,或者叫“没有参数,并返回 Void 类型的函数”。
在 Swift 中,使用函数类型就像使用其他类型一样。例如,你可以定义一个类型为函数的常量或变量,并将适当 的函数赋值给它:

func addTwoInts(a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
    return a * b 
}
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))")
//有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
  • 函数类型作为参数类型,你可以用 (Int, Int) -> Int 这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现留给函 数的调用者来提供。
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
     print("Result: \(mathFunction(a, b))")
 }
 printMathResult(addTwoInts, 3, 5)

函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。闭包中的代码能访问闭包所建作用域中能得到的变 量和函数,即使闭包是在一个不同的作用域被执行的。

可以使用 {} 来创建 一个匿名闭包。使用 in 将参数和返回值类型声明与闭包函数体进行分离。

numbers.map({
     (number: Int) -> Int in
     let result = 3 * number
     return result
})

如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型
和返回值。单个语句闭包会把它语句的值当做结果返回。

let mappedNumbers = numbers.map({ number in 3 * number })
 print(mappedNumbers)

对象和类

类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。

class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    init(name: String) {
        self.name = name
    }
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    } 
}

子类如果要重写父类的方法的话,需要用 override 标记——如果没有添加 override 就重写父类方法的话编译器 会报错。编译器同样会检测 override 标记的方法是否确实在父类中。

class Square: NamedShape {
     var sideLength: Double
     init(sideLength: Double, name: String) {
         self.sideLength = sideLength
         super.init(name: name)
         numberOfSides = 4
}
     func area() ->  Double {
         return sideLength * sideLength
}
     override func simpleDescription() -> String {
         return "A square with sides of length \(sideLength)."
} }
 let test = Square(sideLength: 5.2, name: "my test square")
 test.area()
 test.simpleDescription()

枚举和结构体

枚举

使用 enum 来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
c   ase Jack, Queen, King
     func simpleDescription() -> String {
         switch self {
         case .Ace:
             return "ace"
         case .Jack:
             return "jack"
         case .Queen:
             return "queen"
         case .King:
             return "king"
         default:
             return String(self.rawValue)
         }
} }
 let ace = Rank.Ace
 let aceRawValue = ace.rawValue

在上面的例子中,枚举原始值的类型是 Int ,所以你只需要设置第一个原始值。剩下的原始值会按照顺序赋值。
可以使用使用 rawValue 属性来访问一个枚举成员的原始值。

if let convertedRank = Rank(rawValue: 3) {
     let threeDescription = convertedRank.simpleDescription()
}

stuct 结构体

使用 struct 来创建一个结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就 是结构体是传值,类是传引用。

struct Card {
     var rank: Rank
     var suit: Suit
     func simpleDescription() -> String {
         return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
     }
 }
 let threeOfSpades = Card(rank: .Three, suit: .Spades)
 let threeOfSpadesDescription = threeOfSpades.simpleDescription()

协议和扩展

协议

协议声明了其它类可以调用的编程接口,这有点类似与java里的接口,它使得类直接的通信变的简单明了。(参考自:http://www.tuicool.com/articles/iemIbq)

Swift 语言简介_第1张图片
protocolOne.jpeg

协议使用 protocol 来声明一个协议。

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

类、枚举和结构体都可以实现协议。

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
     func adjust() {
         simpleDescription += "  Now 100% adjusted."
     }
 }
 var a = SimpleClass()
 a.adjust()
 let aDescription = a.simpleDescription

注意声明 SimpleStructure 时候 mutating 关键字用来标记一个会修改结构体的方法。 SimpleClass 的声明不需要 标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。

struct SimpleStructure: ExampleProtocol {
     var simpleDescription: String = "A simple structure"
     mutating func adjust() {
         simpleDescription += " (adjusted)"
     }
 }
 var b = SimpleStructure()
 b.adjust()
 let bDescription = b.simpleDescription

扩展

使用 extension 来为现有的类型添加功能,比如新的方法和计算属性。你可以使用扩展在别处修改定义,甚至是 从外部库或者框架引入的一个类型,使得这个类型遵循某个协议

extension Int: ExampleProtocol {
     var simpleDescription: String {
         return "The number \(self)"
     }
     mutating func adjust() {
self += 42 }
 }
 print(7.simpleDescription)

错误处理

你可以使用错误处理(error handling)来应对程序执行中可能会遇到的错误条件。
当一个函数遇到错误条件,它能报错。调用函数的地方能抛出错误消息并合理处理。

func canThrowAnError() throws { // 这个函数有可能抛出错误
}

一个函数可以通过在声明中添加 throws 关键词来抛出错误消息。当你的函数能抛出错误消息时, 你应该在表达式 中前置 try 关键词。

do {
    try canThrowAnError() // 没有错误消息抛出
} catch {
    // 有一个错误消息抛出
}

一个 do 语句创建了一个新的包含作用域,使得错误能被传播到一个或多个 catch 从句。 这里有一个错误处理如何用来应对不同错误条件的例子。

func makeASandwich() throws {
    // ...
}
do {
    try makeASandwich()
    eatASandwich()
} catch Error.OutOfCleanDishes {
    washDishes()
} catch Error.MissingIngredients(let ingredients) {
    buyGroceries(ingredients)
}

断言

可选类型可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺 失或者值并不满足特定的条件,你的代码可能没办法继续执行。这时,你可以在你的代码中触发一个断言(asser tion)来结束代码运行并通过调试来找到值缺失的原因。

使用断言进行调试

断言会在运行时判断一个逻辑条件是否为 true 。从字面意思来说,断言“断言”一个条件是否为真。你可以使用 断言来保证在运行其他代码之前,某些重要的条件已经被满足。如果条件判断为 true ,代码运行会继续进行;如 果条件判断为 false ,代码执行结束,你的应用被终止。

let age = -3
assert(age >= 0, "A person's age cannot be less than zero")

注意:
当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。

何时使用断言

当条件可能为假时使用断言,但是最终一定要保证条件为真,这样你的代码才能继续运行。断言的适用情景:
• 整数类型的下标索引被传入一个自定义下标脚本实现,但是下标索引值可能太小或者太大。
• 需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。
• 一个可选值现在是 nil ,但是后面的代码运行需要一个非 nil 值。

参考文献

  1. The Swift Programming Language (Swift 2.2)

参考网址

  1. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html
  2. https://swift.org
  3. https://github.com/apple/swift

你可能感兴趣的:(Swift 语言简介)