Skip to content

Swift 基础部分(The Basics)

cheyiliu edited this page Aug 1, 2016 · 17 revisions
  • Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示“那儿有一个值,并且它等于 x ”或 者“那儿没有值”。(不提供烦人的默认值)
  • “类型转换”
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one) //用现有的 UInt8 来创建一个新的 UInt16

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine //用three构造一个新的double,再计算
//强制解析: 当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping)。
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要惊叹号来获取值,强制解析


//自动解析: 你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析。
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号,隐式可选类型


//可选绑定(optional binding): 可以用来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
var str2: String?
if let x = str2 {
   print(x)
} else {
   print("nil")
}


//可选链(Optional Chaining)
class Person {
   var pet: Pet?
}

class Pet {
   var name: String
   
   var favoriteToy: Toy?
   
   init (name: String) {
       self.name = name
   }
}

class Toy {
   var name: String
   
   init (name: String) {
       self.name = name
   }
}

let jackon = Person()
jackon.pet = Pet(name: "Max")
jackon.pet?.favoriteToy = Toy(name: "Ball")

if let pet = jackon.pet {
   if let toy = pet.favoriteToy {
       toy.name
   }
}

//基本上,Optional Chaining就是总是返回一个Optional的值,只要这个Chaining中有一个值为nil,整条Chaining就为nil
if let toy = jackon.pet?.favoriteToy {
   toy.name
}
enum VendingMachineError: ErrorType {
   case InvalidSelection                    //选择无效
   case InsufficientFunds(coinsNeeded: Int) //金额不足
   case OutOfStock                          //缺货
}

func canThrowErrors(money:Int) throws -> String {
   defer{
       print("defer, canThrowErrors")
   }
   if money<101 {
       print("exception throws")
       throw VendingMachineError.InsufficientFunds(coinsNeeded: 101)
   }
   return "canThrowErrors run end"
}

func testExp() {
   defer{
       print("defer, test")
   }
   
   do{
       var result: String
       try result = canThrowErrors(1000)
       print(result)
       
       var result2: String?
       result2 = try? canThrowErrors(100)
       print(result2)
   } catch is VendingMachineError {
       print("some VendingMachineError catched")
   }catch{
       print("some other catched")
   }
}

testExp()
  • 空合运算符(??)将对可选类型 进行空判断,如果 包含一个值就进行解封,否则就返回一个默认值 .这个运算符有两个条件:1 表达式 必须是Optional类型 2默认值 的类型必须要和 存储值的类型保持一致
  • Swift 的 String 类型是值类型。 如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/ 方法中传递时,会进行值拷贝
  • 集合:数字 集合 字典
  • guard 我们可以使用 guard 语句来要求条件必须为真 时,以执行 guard 语句后的代码。不同于 if 语句,一个 guard 语句总是有一个 else 分句,如果条件不为真则执 行 else 分句中的代码。
  • 检测 API 可用性
if #available(iOS 8, *) {
       // iOS 8 及其以上系统运行
}

guard #available(iOS 8, *) else {
   return //iOS 8 以下系统就直接返回
}

  • 函数类型,每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。
func changeInt(inout intParam: Int)  {
   intParam += 1
}
var methodv = changeInt
print(methodv is (inout Int) -> Void)

var intparam: Int = 100;
changeInt(&intparam)
print(intparam)

//函数类型作为返回值
func stepForward(input: Int) -> Int {
   return input + 1
}
func stepBackward(input: Int) -> Int {
   return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
   return backwards ? stepBackward : stepForward
}
var result = chooseStepFunction(false)(5)
print(result)
  • 闭包(函数是特殊闭包),和类一样,必要也是引用类型 TODO深入体会
let names = ["AAA", "CCC"]
func backwards(s1: String, s2: String) -> Bool {
   return s1 > s2
}
var reversed = names.sort(backwards)
print(reversed)

reversed = names.sort({ (s1: String, s2: String) -> Bool in
   return s1 < s2
})
print(reversed)

reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 >  s2 } )
print(reversed)

reversed = names.sort( { s1, s2 in return s1 < s2 } )
print(reversed)

reversed = names.sort( { $0 > $1 } )
print(reversed)

reversed = names.sort(<)
print(reversed)

reversed = names.sort() { $0 > $1 }
print(reversed)

reversed = names.sort { $0 < $1 }
print(reversed)



let digitNames = [
   0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
   5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
   (number) -> String in
   var number = number
   var output = ""
   while number > 0 {
       output = digitNames[number % 10]! + output
       number /= 10
   }
   return output
}
print(strings)



func makeIncrementor(forIncrement amount: Int) -> () -> Int {
   var runningTotal = 0
   func incrementor() -> Int {
//        var runningTotal = 0 //试试这行,体会“捕获值”,其实就是作用域,引用类型
       runningTotal += amount
       return runningTotal
   }
   return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
  • 枚举
enum Barcode {
   case UPCA(Int, Int, Int, Int)
   case QRCode(String)
}
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
   print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
   print("QR code: \(productCode).")
}
  • 类和结构体
  • 结构体和枚举是值类型: 值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。
  • 在 Swift 中,所有的基本类型:整数(Integer)、浮 点数(floating-point)、布尔值(Boolean)、字符串(string)、数组(array)和字典(dictionary),都是 值类型,并且在底层都是以结构体的形式所实现。
  • 类是引用类型, 与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的 是已存在的实例本身而不是其拷贝。
  • 如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒 等运算符: 等价于(===) 不等价于( !== )
  • 结构体实例总是通过值传递,类实例总是通过引用传递。这意味两者适用不同的任务。当你在考虑一个工程项目的数据结构和功能的时候,你需要决定每个数据结构是定义成类还是结构体。 按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
  • 该数据结构的主要目的是用来封装少量相关简单数据值。
  • 有理由预计该数据结构的实例在被赋值或传递时,封装的数据将会被拷贝而不是被引用。
  • 该数据结构中储存的值类型属性,也应该被拷贝,而不是被引用。
  • 该数据结构不需要去继承另一个既有类型的属性或者行为。
  • 属性 (Properties) (包括:存储属性;计算属性;属性观察器;全局变量和局部变量;类型属性;类型属性(就像 C 语言中的静态变量))
  • 方法(Methods) (包括:实例方法 (Instance Methods);self 属性(The self Property);可以选择 变异(mutating) 这个方 法,然后方法就可以从方法内部改变它的属性;类型方法 (Type Methods);)
struct LevelTracker {
   static var highestUnlockedLevel = 1
   static func unlockLevel(level: Int) {
       if level > highestUnlockedLevel { highestUnlockedLevel = level }
   }
   static func levelIsUnlocked(level: Int) -> Bool {
       return level <= highestUnlockedLevel
   }
   
   var currentLevel = 1
   mutating func advanceToLevel(level: Int) -> Bool {
       if LevelTracker.levelIsUnlocked(level) {
           currentLevel = level
           return true
       } else {
           return false
       }
   }
}

class Player {
   var tracker = LevelTracker()
   let playerName: String
   func completedLevel(level: Int) {
       LevelTracker.unlockLevel(level + 1)
       tracker.advanceToLevel(level + 1)
   }
   init(name: String) {
       playerName = name
   }
}
var player = Player(name: "Argyrios")
player.completedLevel(1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")

player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) {
   print("player is now on level 6")
} else {
   print("level 6 has not yet been unlocked")
}
  • 下标脚本(Subscripts) 举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 meArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key] 。
struct Matrix {
   let rows: Int, columns: Int
   var grid: [Double]
   init(rows: Int, columns: Int) {
       self.rows = rows
       self.columns = columns
       grid = Array(count: rows * columns, repeatedValue: 0.0)
   }
   func indexIsValidForRow(row: Int, column: Int) -> Bool {
       return row >= 0 && row < rows && column >= 0 && column < columns
   }
   subscript(row: Int, column: Int) -> Double {
       get {
           assert(indexIsValidForRow(row, column: column), "Index out of range")
           return grid[(row * columns) + column]
       }
       set {
           assert(indexIsValidForRow(row, column: column), "Index out of range")
           grid[(row * columns) + column] = newValue
       }
   }
}

var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

//let someValue = matrix[2, 2]
// 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度
  • 继承(Inheritance) (你可以通过把方法,属性或下标脚本标记为 final 来防止它们被重写,只需要在声明关键字前加上 final 特性即 可。(例如: final var , final func , final class func , 以及 final subscript ))
class Vehicle {
   var currentSpeed = 0.0
   var description: String {
       return "traveling at \(currentSpeed) miles per hour"
   }
   func makeNoise() {
       // 什么也不做-因为车辆不一定会有噪音
   }
}
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour

class Bicycle: Vehicle {
   var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour

class Train: Vehicle {
   override func makeNoise() {
       print("Choo Choo")
   }
}
let train = Train()
train.makeNoise()
// prints "Choo Choo"

class Car: Vehicle {
   var gear = 1
   override var description: String {
       return super.description + " in gear \(gear)"
   }
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3

class AutomaticCar: Car {
   override var currentSpeed: Double {
       didSet {
           gear = Int(currentSpeed / 10.0) + 1
       }
   }
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4

  • 构造过程(Initialization)
  • 构造过程是使用类、结构体或枚举类型一个实例的准备过程。在新实例可用前必须执行这个过程,具体操作包括 设置实例中每个存储型属性的初始值和执行其他必须的设置或初始化工作。
  • 类的实例也可以通过定义析构器( deinitializer )在实例释放之前执行特定的清除工作。
  • 跟函数和方法参数相同,构造参数也存在一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参 数名字。然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时,主要通过构造器中的 参数名和类型来确定需要调用的构造器。正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名 字,Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名,就相当于在每个构造参数之前加了一 个哈希符号。
  • 如果你定制的类型包含一个逻辑上允许取值为空的存储型属性--不管是因为它无法在初始化时赋值,还是因为它 可以在之后某个时间点可以赋值为空--你都需要将它定义为可选类型 optional type 。可选类型的属性将自动初 始化为空 nil ,表示这个属性是故意在初始化时设置为空的。
  • 你可以在构造过程中的任意时间点修改常量属性的值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
  • 如果结构体和类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体和类创建一个默 认构造器。这个默认构造器将简单的创建一个所有属性值都设置为默认值的实例。
  • 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。
  • 指定构造器和便利构造器(指定构造器必须调用其直接父类的的指定构造器。便利构造器必须调用同一类中定义的其它构造器。便利构造器必须最终以调用一个指定构造器结束。)
  • 两段式构造过程(Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储型属性通过引入它们的类的构造器来设置初始 值。当每一个存储型属性值被确定后,第二阶段开始,它给每个类一次机会在新实例准备使用之前进一步定制它 们的存储型属性。)
  • 阶段 1
  • 某个指定构造器或便利构造器被调用;此时阶段1开始。
  • 完成新实例内存的分配,但此时内存还没有被初始化;
  • 指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化;
  • 指定构造器将调用父类的构造器,完成父类属性的初始化;
  • 这个调用父类构造器的过程沿着构造器链一直往上执行,直到到达构造器链的最顶部;
  • 当到达了构造器链最顶部,且已确保所有实例包含的存储型属性都已经赋值,这个实例的内存被认为已经完 全初始化。此时阶段1完成。
  • 阶段 2
  • 从顶部构造器链一直往下,每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问 self 、修改它的属性并调用实例方法等等。
  • 最终,任意构造器链中的便利构造器可以有机会定制实例和使用 self 。
  • 指定构造器和便利构造器的区别(调用的横纵方向差异)
  • 可失败构造器( init? )
  • 必要构造器
//初始化
struct Fahrenheit {
   var temperature: Double
   init() {
       temperature = 32.0
   }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit") // 输出 "The default temperature is 32.0° Fahrenheit”


struct Celsius {
//    let constInt: Int = 1 //error: 这句和构造函数,只能初始化一次
   let constInt: Int
   var temperatureInCelsius: Double
   var optMember: String?
   init(fromFahrenheit fahrenheit: Double) {
       temperatureInCelsius = (fahrenheit - 32.0) / 1.8
       constInt = 10000000
   }
   init(fromKelvin kelvin: Double) {
       temperatureInCelsius = kelvin - 273.15
       constInt = 10000000
   }
   init(_ celsius: Double){
       temperatureInCelsius = celsius
       constInt = 10000000
   }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
print(boilingPointOfWater)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
print(freezingPointOfWater)
var xCelsius = Celsius(100)
//xCelsius.optMember = "optStr"
print(xCelsius)
print(xCelsius.optMember)


struct Rect2 {
   var origin = Point()
   var size = Size()
   init() {}
   init(origin: Point, size: Size) {
       self.origin = origin
       self.size = size
   }
   init(center: Point, size: Size) {
       let originX = center.x - (size.width / 2)
       let originY = center.y - (size.height / 2)
       self.init(origin: Point(x: originX, y: originY), size: size)
   }
}



class Vehicle2 {
   var numberOfWheels = 0
   var description: String {
       return "\(numberOfWheels) wheel(s)"
   }
}
class Bicycle2: Vehicle2 {
   override init() {
//      numberOfWheels = 2 // error
       super.init()
       numberOfWheels = 2
   }
}

class Food {
   var name: String
   init(name: String) {
       self.name = name
   }
   convenience init() {
       self.init(name: "[Unnamed]")
   }
}

class RecipeIngredient: Food {
   var quantity: Int
   init(name: String, quantity: Int) {
       self.quantity = quantity
       super.init(name: name)
   }
override  convenience init(name: String) {
       self.init(name: name, quantity: 1)
       quantity = 1
   }
}


struct Animal {
   let species: String
   init?(species: String) {// 可失败构造器
       if species.isEmpty { return nil }
       self.species = species
   }
}

  • 析构过程(Reinitialization) 析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用。析构器用关键字 deinit 来标示,类 似于构造器要用 init 来标示。

  • 自动引用计数(Automatic Reference Counting)

  • 解决实例之间的循环强引用(Swift 提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:弱引用(weak reference)和无 主引用(unowned reference))

  • 解决闭包引起的循环强引用(跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。)

  • 可空链式调用(Optional Chaining) (john.residence?.address?.buildingIdentifier())

  • 错误处理(Error Handling)

  • 类型转换(Type Casting) (类型转换在 Swift 中使用 is 和 as 操作符实现) (向下转型(Downcasting)用类型转换操作符(as? 或 as!))


class MediaItem {
   var name: String
   init(name: String) {
       self.name = name
   }
}
class Song: MediaItem {
   var artist: String
   init(name: String, artist: String) {
       self.artist = artist
       super.init(name: name)
   }
}
class Movie: MediaItem {
   var director: String
   init(name: String, director: String) {
       self.director = director
       super.init(name: name)
   }
}

let library = [
   Movie(name: "Casablanca", director: "Michael Curtiz"),
   Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
   Movie(name: "Citizen Kane", director: "Orson Welles"),
   Song(name: "The One And Only", artist: "Chesney Hawkes"),
   Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be [MediaItem]

var movieCount = 0
var songCount = 0
for item in library {
   if item is Movie {
       movieCount += 1
   } else if item is Song {
       songCount += 1
   }
}
print("Media library contains \(movieCount) movies and \(songCount) songs")

for item in library {
   if let movie = item as? Movie {
       print("Movie: '\(movie.name)', dir. \(movie.director)")
   } else if let song = item as? Song {
       print("Song: '\(song.name)', by \(song.artist)")
   }
}

  • Swift为不确定类型提供了两种特殊类型别名: AnyObject可以代表任何class类型的实例;Any可以表示任何类型,包括方法类型(function types)。
// Movie的定义见上面
let someObjects: [AnyObject] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott")
]
for object in someObjects {
    let movie = object as! Movie
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}
// 下转 someObjects 数组为 [Movie] 类型
for movie in someObjects as! [Movie] {
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}


var things = [Any]()
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
//things.append((3.0, 5.0)) // compile error
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
for thing in things {
   switch thing {
   case 0 as Int:
       print("zero as an Int")
   case 0 as Double:
       print("zero as a Double")
   case let someInt as Int:
       print("an integer value of \(someInt)")
   case let someDouble as Double where someDouble > 0:
       print("a positive double value of \(someDouble)")
   case is Double:
       print("some other double value that I don't want to print")
   case let someString as String:
       print("a string value of \"\(someString)\"")
   case let (x, y) as (Double, Double):
       print("an (x, y) point at \(x), \(y)")
   case let movie as Movie:
       print("a movie called '\(movie.name)', dir. \(movie.director)")
   case let stringConverter as String -> String:
       print(stringConverter("Michael"))
   default:
       print("something else")
   }
}
  • 嵌套类型(Nested Types)
struct BlackjackCard {
   // 嵌套定义枚举型Suit
   enum Suit: Character {
       case Spades = "j", Hearts = "q", Diamonds = "k", Clubs = "a"
   }
   // 嵌套定义枚举型Rank
   enum Rank: Int {
       case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
       case Jack, Queen, King, Ace

       struct Values {
           let first: Int, second: Int?
       }
       var values: Values {
           switch self {
           case .Ace:
               return Values(first: 1, second: 11)
           case .Jack, .Queen, .King:
               return Values(first: 10, second: nil)
           default:
               return Values(first: self.rawValue, second: nil)
           }
       }
   }
   // BlackjackCard 的属性和方法 
   let rank: Rank, suit: Suit
   var description: String {
       var output = "suit is \(suit.rawValue),"
       output += " value is \(rank.values.first)"
       if let second = rank.values.second {
           output += " or \(second)"
       }
       return output
   }
}
  • 扩展(Extensions) 扩展就是向一个已有的类、结构体、枚举类型或者协议类型添加新功能(functionality)。这包括在没有权限获 取原始源代码的情况下扩展类型的能力(即逆向建模)。(注意:扩展可以对一个类型添加新的功能,但是不能重写已有的功能。)
// 扩展
struct Size {
   var width = 0.0, height = 0.0
}
struct Point {
   var x = 0.0, y = 0.0
}
struct Rect {
   var origin = Point()
   var size = Size()
}

let defaultRect = Rect()
let memberwiseRect = Rect(
   origin: Point(x: 2.0, y: 2.0),
   size: Size(width: 5.0, height: 5.0)
)

extension Rect {
   init(center: Point, size: Size) {
       let originX = center.x - (size.width / 2)
       let originY = center.y - (size.height / 2)
       self.init(origin: Point(x: originX, y: originY), size: size)
   }
}

let centerRect = Rect(
   center: Point(x: 4.0, y: 4.0),
   size: Size(width: 3.0, height: 3.0)
)


extension Int {
   func repetitions(task: () -> ()) {
       for _ in 0..<self {
           task()
       }
   }
}

3.repetitions({
   print("Hello!")
})
//使用 trailing 闭包使调用更加简洁
3.repetitions{
   print("Goodbye!")
}


extension Int {
   mutating func square() {
       self = self * self
   }
}
var someInt = 3
someInt.square()


extension Int {
   subscript(var digitIndex: Int) -> Int {
       var decimalBase = 1
       while digitIndex > 0 {
           decimalBase *= 10
           digitIndex -= 1
       }
       return (self / decimalBase) % 10
   }
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7



extension Int {
   enum Kind {
       case Negative, Zero, Positive
   }
   var kind: Kind {
       switch self {
       case 0:
           return .Zero
       case let x where x > 0:
           return .Positive
       default:
           return .Negative
       }
   }
}
3.kind
(-1).kind

func printIntegerKinds(numbers: [Int]) {
   for number in numbers {
       switch number.kind {
       case .Negative:
           print("- ", terminator: "")
       case .Zero:
           print("0 ", terminator: "")
       case .Positive:
           print("+ ", terminator: "")
       }
   }
   print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
  • 协议(Protocols) 定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。任意能够满足协议要求的类型被称为遵循这个协议。
protocol Togglable {
   mutating func toggle()
}

enum OnOffSwitch: Togglable {
   case Off, On
   mutating func toggle() {
       switch self {
       case Off:
           self = On
       case On:
           self = Off
       }
   }
}
var lightSwitch = OnOffSwitch.Off
lightSwitch.toggle()



protocol SomeProtocol1 {
   init(someParameter: Int)
}

class SomeClass1: SomeProtocol1 {
   required init(someParameter: Int) {
       //构造器实现 
   }
}

protocol SomeInheritedProtocol {
}
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol { // 类专属协议
}



protocol Named {
   var name: String { get }
}
protocol Aged {
   var age: Int { get }
}
struct Person1: Named, Aged {
   var name: String
   var age: Int
}
//协议合成
func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
   print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person1(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)



//可选协议
@objc protocol CounterDataSource {
   optional func incrementForCount(count: Int) -> Int
   optional var fixedIncrement: Int { get }
}
class ThreeSource: CounterDataSource {
   @objc let fixedIncrement = 3
}
class Counter {
   var count = 0
   var dataSource: CounterDataSource?
   func increment() {
       if let amount = dataSource?.incrementForCount?(count) {
           count += amount
       } else if let amount = dataSource?.fixedIncrement {
           count += amount
       }
   }
}
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
   counter.increment()
   print(counter.count)
}
  • 泛型(Generics)
//类型参数化
func swapTwoInts(inout a: Int, inout _ b: Int) {
   let temporaryA = a
   a = b
   b = temporaryA
}
func swapTwoStrings(inout a: String, inout _ b: String) {
   let temporaryA = a
   a = b
   b = temporaryA
}
func swapTwoDoubles(inout a: Double, inout _ b: Double) {
   let temporaryA = a
   a = b
   b = temporaryA
}

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


func swapTwoValues<T>(inout a: T, inout _ b: T) {
   let temporaryA = a
   a = b
   b = temporaryA
}
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
print(someString)
print(anotherString)
// someString 现在等于 "world", anotherString 现在等于 "hello"

struct Stack<T> {
   var items = [T]()
   mutating func push(item: T) {
       items.append(item)
   }
   mutating func pop() -> T {
       return items.removeLast()
   }
}

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
print(stackOfStrings)
let fromTheTop = stackOfStrings.pop()
print(stackOfStrings)

extension Stack {
   var topItem: T? {
       return items.isEmpty ? nil : items[items.count - 1]
   }
}

print(stackOfStrings.topItem)
if let topItem = stackOfStrings.topItem {
   print("The top item on the stack is \(topItem).")
}

//T: Equatable
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
   for (index, value) in array.enumerate() {
       if value == valueToFind {
           return index
       }
   }
   return nil
}

var someArray = [1,2,3,5,6]
if let index = findIndex(someArray, 6) {
   print(index)
}

//关联类型(Associated Types)
protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}

struct IntStack: Container {
   // IntStack的原始实现
   var items = [Int]()
   mutating func push(item: Int) {
       items.append(item)
   }
   mutating func pop() -> Int {
       return items.removeLast()
   }
   // 遵循Container协议的实现 typealias ItemType = Int
   mutating func append(item: Int) {
       self.push(item)
   }
   var count: Int {
       return items.count
   }
   subscript(i: Int) -> Int {
       return items[i]
   }
}

struct Stack2<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
       items.append(item)
   }
   mutating func pop() -> T {
       return items.removeLast()
   }
   // conformance to the Container protocol
   mutating func append(item: T) {
       self.push(item)
   }
   var count: Int {
       return items.count
   }
   subscript(i: Int) -> T {
       return items[i]
   }
}

//where子句
func allItemsMatch<C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {
   // 检查两个Container的元素个数是否相同
   if someContainer.count != anotherContainer.count {
       return false
   }
   // 检查两个Container相应位置的元素彼此是否相等 
   for i in 0..<someContainer.count {
       if someContainer[i] != anotherContainer[i] {
           return false
       }
   }
   // 如果所有元素检查都相同则返回true
   return true
}

var stackOfStrings1 = Stack2<String>()
stackOfStrings1.push("uno")
stackOfStrings1.push("dos")
stackOfStrings1.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
extension Array: Container {}
if allItemsMatch(stackOfStrings1, anotherContainer: arrayOfStrings) {
   print("All items match.")
} else {
   print("Not all items match.")
}
  • 访问控制(Access Control) TODO
Clone this wiki locally