Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Swift 入门笔记

swift 入门笔记

变量

let 声明常量,var 声明变量

var myVariable = 2
myVariable = 3
let myConstant = 4

let explicitDouble: Double  = 70 // 显式声明类型

变量的值不会做隐式的类型转换,如果需要转换类型,需要显式实例化,如:

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

print(widthLabel)

有一个简答的方法在字符串中引用变量,使用 \(),如:

let apples = 3
let oranges = 4
let fruitsSummary = "I have \(apples + oranges) pieces of fruit."

使用 [] 来创建数组或者字典,同样地使用 target[index] 来获取元素:

var list = ["apple", "orange", "banana"]
var list[1] = "pear"

var jobs = [
  "Peter": "Developer",
  "Mike": "Worker"
]

jobs["Mike"] = "Writer"

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

let emptyArray = [String]()

let emptyDictionary = [String: Float]()

// 如果类型可以推断,那么可以不显式声明类型
shoppingList = []
occupations = [:]

控制流

使用 ifswitch 来进行条件判断,使用 for-inforwhilerepeat-while 来进行循环控制。

条件或者循环变量的括号可以写也可以不写,执行的代码的 {} 则是必须的。

条件判断

let scores = [75, 43, 103, 87, 12]
var teamScore = 0

for score in scores {
  if score > 50 {
    teamScore += 3
  } else {
    teamScore += 1
  }
}

print(teamScore)

if 语句中,条件判断必须是 Boolean 类型,如上, if score { ... } 则会报错。

可以使用 letif 搭配来判断可能是 nil 的值,在类型声明后加 ? 来表示这个值是可选的,可能是 nil。

在 swift 中的 ? 很特别,如果在 ? 之前的值是 nil,那么在 ? 之后的会被忽略,并且整个表达式的值为 nil。

var optionalString: String? = "Hello"
print(optionalString == nil)

var optionalName: String? = "Boom Lee"
var greeting = "Hello!"
if let name = optionalName {
  greeting = "Hello, \(name)"
}

let 可以用于传递匹配对应的值,例如:

let vegetable = "red pepper"

switch vegetable {  
case "celery":
  print("1")
case "cucumber", "watercress":
  print("2")
case let x where x.hasSuffix("pepper"):
  print("3")
default:
  print("default")
}

留意 case "cucumber", "watercress": 可以这么使用来处理或逻辑。

留意 case let x where x.hasSuffix("pepper"): 使用 let 来获取对应的值,并且使用 where 来进行判断。

这里不需要 break,默认的逻辑是不会接着 case 执行下次。

循环逻辑

使用 fon-in 来循环遍历字典。字典是一种无序集合的数据类型,for-�in 提供了对应的 key-value。

let numbers = [
  "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 numbers {
  for number in numbers {
    if number > largest {
      largest = number
    }
  }
}

print(largest)

使用 while 来循环代码直到某一个状态值符合条件。使用 repeat,把 while 放在代码块之后,确保代码块至少至少执行一次。

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

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

可以使用 ..< 在循环中维持一个索引值,例如:

var first = 0
for i in 0..<4 {
  first += i
}
print(first)

// 等价于

var second = 0
for var i = 0; i < 4; i++ {
  second += i
}
print(second)

函数和闭包

使用 func 来声明函数。使用 -> 来声明函数的返回类型。

func greet(name: String, day: String) -> String {
  return "Hello \(name), today is \(day)"
}

greet("Boom", day: "Tuesday")

swift 的函数可以使用 () 来返回多个值,并且这些值可以使用 name 或者序号来获取。

func calculate(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
  var min = scores[0]
  var max = scores[0]
  var sum = 0

  for score in scores {
    if score > max {
      max = score
    } else if score < min {
      min = score
    }
    sum += score
  }

  return (min, max, sum)
}

let statistics = calculate([5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)

swift 的函数可以接受不定量的参数,将其存放于一个数组中:

func sumOf(numbers: Int...) -> Int {
  var sum = 0
  for number in numbers {
    sum += number
  }

  return sum
}

sumOf()
sumOf(32, 11, 23)

函数是可以嵌套的,并且内部的函数可以访问在外部函数声明的变量。

你可以使用嵌套的函数来组织很长或者很复杂的代码。函数在 swift 也是第一类型,这意味着你可以在函数中返回函数,或者使用函数作为参数。

func makeIncrementer() -> (Int -> Int) {
  func addOne(number: Int) -> Int {
    return 1 + number
  }

  return addOne
}

var incrementer = makeIncrementer()
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
  for item in list {
    if condition(item) {
      return true
    }
  }
  return false
}

func lessThenTen(number: Int) -> Bool {
  return number < 10
}

var numbers = [20, 19, 7, 11]
hasAnyMatches(numbers, condition: lessThenTen)

在 swift 中,函数实际上是一种闭包,即可延后调用的代码块。在闭包中的代码可以访问创建闭包时作用域中的变量和函数。

可以在 swift 中使用 {} 来创建一个闭包,使用 in 来区分参数,返回类型和代码块内容。

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

使用闭包时有多种方式,如果是一个闭包的数据类型是已知的,例如函数的一个回调,那么你可以忽略参数类型,或者返回类型。单个语句的闭包会直接返回语句表达式的值。

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

你可以使用序号来引用参数,在很短的闭包中这种方式非常有用。

闭包是函数唯一的参数,可以直接忽略括号。

let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)

对象和类

使用 class 加类名可以创建一个类。声明类属性如同声明变量和常量一样,但是它在类的上下文中。方法和函数的声明也是类似的。

class Shape {
  var numberOfSides = 0

  func simpleDescription() -> String {
    return "A shape with \(numberOfSides) sides."
  }
}

创建一个类的实例,直接在类名后加 () 即可,如:

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

构造函数的话,使用 init 来创建:

class NamedSpace {
  var numberOfSides: Int = 0
  var name: String

  init(name: String) {
    self.name = name
  }

  ...
}

留意 self 可以用来区分 name 属性和 name 参数。传递给 init 的参数就和函数调用是一样的,实例化时传递即可。

使用 deinit 来创建一个析构函数,当一个对象回收时,如果你需要做一些清理工作的话,可以在 deinit 方法中处理。

类继承只需要在类声明后加要继承的父类,使用 : 即可。没有要求类必须继承于某一个根类,你可以视需要而定。

在子类中要覆写父类的方法时,需要在方法声明前加 override,没有的话,编译时会报错。编辑器也会发现那些加了 override 但是却不是覆写父类的方法。

class Square: NamedSpace {
  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()

除了简单的存储外,属性可以拥有 getter 和 setter 方法:

var perimeter: Double {
  get {
    return 3.0 * sideLength
  }

  set {
    sideLength = newValue / 3.0
  }
}

在 setter 中可以使用 newValue 名称来获取新设置的值,你也可以在 set 声明中使用 () 来使用自定义的名称。

类的初始化方法中一般是有三个不同步骤:

  1. 设置子类声明的属性值
  2. 调用父类的初始化方法
  3. 修改子类定义的属性值,一些额外的初始化方法的调用等

如果你不需要计算属性的值,不希望使用 setter,但是需要在设置属性之前或者之后执行一些代码,这个时候可以使用 willSetdidSet

class TriangleAndSquare {
  var triangle: EquilateralTriangle {
    willSet {
      square.sideLength = newValue.sideLength
    }
  }

  var square: Square {
    willSet {
      triangle.sideLength = square.sideLength
    }
  }

  ...
}

枚举和结构体

枚举 enum

使用 enum 来创建枚举类型,可以像类一样拥有方法:

enum Rank: Int {
  case Ace = 1
  case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
  case Jack, Queen, King

  func simpleDescription() -> Stirng {
    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,你只需要指定第一个原始值,如 case Ace = 1,那么剩余的值会自动按序赋予。你也可以使用字符串或者浮点数作为枚举的原始值类型。

使用 rawValue 来获取枚举的一个成员的原始值。

你也可以通过的枚举的 init 方法传入一个原始值来进行枚举的实例化。如:

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

枚举成员的值可以拥有一个确切的原始值,如果没有确切的原始值,也可以不用指定。

enum Suit {
  case Spades, Hearts, Diamonds, Clubs

  func simpleDescription() -> String {
    switch self {
    case .Spades:
      return "spades"
    case .Hearts:
      return "hearts"
    case .Diamonds:
      return "diamonds"
    case .Clubs:
      return "clubs"
    }
  }
}

let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()

留意一下,这里的 Hearts 有两种引用方式,在 hearts 赋值时使用全称,Suit.Hearts。而在 swict 中直接使用 .Hearts,因为在上下文环境中已经可以确定 self 为 Suit。你可以在已知类型的情况下使用这种简短的写法。

结构体 struct

使用 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()

协议和扩展

协议

协议我们可以理解为类似接口的东西,在 swift 中,类,枚举,结构体都可以使用协议:

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

class SimpleClass: Example {
  var simpleDescription: String = "A simple class."
  var anotherProperty: Int = 1
  func adjust() {
    simpleDescription += " Now 100% adjusted."
  }
}

var a = SimpleClass()
a.adjust()

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

注意 mutating 的使用,这个关键词用于表示方法将会修改这个结构体,而类通常默认方法可以修改自身,所以无需使用 mutating 来声明。

扩展

扩展可以用于在已有的类型上添加功能,例如新的方法或者可计算的属性。你可以使用扩展来把协议添加到已有的类型上。

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

泛型

使用 <> 来声明一个泛型的函数或者类型:

func repeatItem<Item>(item: Item, times: Int) -> [Item] {
  var result = [Item]()
  for _ in 0..<times {
    result.append(item)
  }
  return result
}

repeatItem("knock", 3)

enum OptionalValue<T> {
  case None
  case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

swift 推荐的编码风格:https://github.com/raywenderlich/swift-style-guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment