【note】Swift初见笔记

来源:互联网 发布:mysql group by 多列 编辑:程序博客网 时间:2024/05/29 13:04
//: Playground - noun: a place where people can play


import UIKit




// -----------------------Swift初见--------------------------------------
// 简单输出
print("hello, world")
// print可以自定义连接符或者自定义结束符
print(1, 2, 3, 4, separator: "-")
print(1, 2, 3, 4, terminator: "")
print(1, 2, 3, 4, separator: "->", terminator: "->End\n")




// let声明常量,var声明变量
let myConstant = 11


var myVariable1 = 42
myVariable1 = 56




// 可以让编译器推断常量或者变量的类型,也可以自己显式指定
var myVariable2:Double = 6




// 值永远的不会被隐式转换为其他类型,必须显式转换
let string1 = "the label is"
let integer1 = 94
let string2 = string1 + String(integer1)


// 把值转换为字符串的另一种写法
let string3 = "the label is \(integer1)"




// 数组和字典都是用[]创建
var list1 = ["apple", "banana", "orange"]
list1[2] = "pear"


var dic = ["class": "2班", "grade": "1年级"]
dic["class"] = "3班"


// 创建一个空数组或者字典
let emptyArray = [String]()
let emptyDictionary = [String: Float]()




// 如果数组或者字典的类型已经被推断出来,就可以用[]或者[:]清空数组或者字典
list1 = []
dic = [:]




// for和if后面的条件小括号可以省略,但是语句的大括号不能省略
// Swift3中已经不支持++和--,只能 += 1和 -= 1
// if中必须是布尔表达式,不会隐性和0比较
let list2 = [1, 2, 3, 4]
var cnt = 0
for tempitem in list2 {
    if tempitem < 3 {
        cnt += 1
    } else {
        cnt -= 1
    }
}




// 用if和let处理值缺失的情况(用可选值)
// 如果变量的可选值是nil,条件会判断为false,大括号内的语句不会被执行
var optionalName: String? = nil
if let name = optionalName {
    print("hello, \(name)")
}




// ?可以规避实例为nil时,调用实例方法报错的现象,因为当实例为nil时候,因为实例是可选类型,所以语句会直接忽略后面的不再执行,故而不会出现异常(也就是说?前面的值为nil时,?后面的操作会被全部忽略)
// nil不可以用在不是可选值的常量或者变量中,如果一个常量或者变量可能会没有值,那就必须声明为可选值
// 如果声明了可选值但是没有初始化,它的默认值为nil,如果不是可选值,且没有初始化,可以定义,但是必须初始化后才能使用
var myValue: String? = nil




// 如果我们非常确定一个可选值一定有值的话,我们可以用"!"对它进行强制拆包
var myValue2: String? = "hello, everyone!"
print(myValue2!)




// 另一种处理可选值的方法是通过使用??操作符来提供一个默认值,如果不加??,该变量会输出nil
let nickName: String? = nil
let fullName: String = "John"
print("Hi, \(nickName ?? fullName)")  //此时会输出"Hi, John\n"




// switch和case支持任何类型的数据,还支持以下方式:
let vegetable = "red pepper"
switch vegetable {
    case "apple":
        print("1")
    case "banana", "orange":
        print("2")
    case let x where x.hasSuffix("pepper"):
        print("It is a \(x)")
    default:
        print("~~~")
}
// switch语句必须要写default语句,不需要写break语句,因为它匹配成功后就会退出switch语句,不会继续执行




// 使用for-in遍历字典,用两个变量来表示每个键值对,字典里面是一个无序的集合
let dic2 = [
    "apple": [1, 2, 3],
    "orange": [7, 10, 11]
]
for (key, values) in dic2 {
    for value in values {
        if value > 0 {
            //balabala...
        }
    }
}




// 使用while或者repeat while语句
var n = 2
while n < 100 {
    n = n * 2
}
repeat {
    n = n / 2;
} while n > 20




// 不包含上界用..<  包含上界用...
// 如果不希望print换行就写 print("\(i) ", terminator: "")
for i in 0..<4 {
    print("\(i) ", terminator: "")
}
for j in 0...4 {
    print(j)
}




// 使用func声明函数,使用->指定返回值的类型
func greet(person: String, day: String) -> String {
    return "Hi, \(person), today is \(day)"
}




// 我们在写函数的时候,如果不提供参数的标签,那么参数的标签就是参数的名字,我们可以在参数名称前面加上自己想要的文字作为函数的参数标签,如果我们不想使用参数标签的话我们可以在参数名称前面加上"_"
// 下面三个语句,分别使用自定义标签、参数名称以及不使用标签


// 内部使用的时候采用参数名称(内部参数名)
func myfunc1(name: String, Address adr: String) -> Void {
    print("My name is \(name), my address is \(adr)")
}
func myfunc2(name: String, adr: String) -> Void {
    print("My name is \(name), my address is \(adr)")
}
func myfunc3( _ name: String, _ adr: String) -> Void {
    print("My name is \(name), my address is \(adr)")
}
// 外部调用的时候使用的是参数标签名(外部参数名)
myfunc1(name: "John", Address: "1234")
myfunc2(name: "John", adr: "1234")
myfunc3("John", "1234")




// 二进制、八进制、十进制、十六进制
var a1 = 0b100 // 4
var a2 = 0o100 // 64
var a3 = 100 // 100
var a4 = 0x100 // 256
// 十进制指数
var a5 = 1.25e-2 // 0.0125




// 元组:可以将多个类型的值聚合起来: 
// 注意!元组是用小括号括起来的() ; 数组和字典是用大括号括起来的[]
let tuples1 = ("John", 21, 1.78)


// 如果想要分解元组可以这样:
let (name, age, height) = tuples1
print("my name is \(name), my age is \(age), my height is \(height)")


// 如果说只想用name可以用下划线代替想要忽略的值,只指定name变量
let (name2, _, _) = tuples1
print("my name is \(name2)!~~~")


// 元组可以使用类似下标的形式访问,不过是以"tuplesName.0" "tuplesName.1" "tuplesName.2"的形式
print("my name is \(tuples1.0) and my age is \(tuples1.1)")


// 也可以给元组定义标签,这样就可以直接使用标签的名字进行访问啦~~~
let tuples2 = (name: "TomCat", age:"22")
print("hello, my name is \(tuples2.name) and my age is \(tuples2.age)")




// 可以用元组来做到让一个函数返回多个值
func myfunc4(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    let min = scores[0]
    let max = scores[1]
    let sum = 0
    return (min, max, sum)
}




// 函数可以带有可变个数的参数
func func8(arr: Int...) -> Int {
    var sum = 0
    for number in arr {
        sum += number
    }
    return sum
}
func8()
func8(arr: 1, 2, 3)




// 函数可以嵌套,被嵌套的函数可以访问外侧函数的变量
func func5() -> Int {
    var y = 10
    func add() {
        y += 20
    }
    add()
    return y
}




// 函数可以作为返回值
func func6() -> ((Int) -> Int) {
    func func7(number: Int) -> Int {
        return 1 + number
    }
    return func7
}


var value6 = func6() //此时value6是func6的返回值类型,func6的返回值类型是一个函数类型,它表示接收一个int类型,返回一个int类型的函数类型
print(value6(7))  // print "8\n"




// 函数可以作为参数
// 如下condition就是一个函数类型的参数
func func9(arr: [Int], condition: (Int) -> Bool) -> Bool {
    for item in arr {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
func9(arr: numbers, condition: lessThanTen)




// 闭包
// 函数实际上是一种特殊的闭包,它是一段之后能够被调取的代码
// 可以使用{}创建一个匿名闭包,使用in将参数和返回值类型声明与闭包函数体进行分离
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})


// 更简洁的写法:如果一个闭包的类型已知,比如作为一个回调函数,就可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当作结果返回
let value7 = numbers.map({number in 3 * number})
print(value7)


// 可以通过参数的位置而不是参数名字来引用参数
// 如果一个闭包是作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面
// 当一个闭包是传给函数的唯一参数,可以完全忽略括号
let arr2 = numbers.sorted { $0 > $1 }
print(arr2)




// 使用class来创建一个类
// 使用一个构造函数来初始化类实例,使用init来创建一个构造器
class className1 {
    var value = 0
    var name = "hahaha"
    init(value: Int) {
        self.value = value
    }
    func func10() -> String {
        return "A shape with \(value) sides"
    }
}




// 创建一个类的实例,不是new不是new不是new!!是在类名后面加括号。
// 使用点来访问实例的属性和方法
var instanceName1 = className1(value: 5)
instanceName1.value = 2
var stringName2 = instanceName1.func10()




// 子类在后面加上“:父类名字”就能继承自父类~创建类的时候并不需要一个标准的根类,所以可以忽略父类
// 如果要重写父类的方法,必须使用override标记(如果没有添加override就重写父类方法的话编译器会报错)。编译器也同样会检测override标记的方法是否确实在父类中
class className2: className1 {
    var sideLength: Double
    init(sideLength: Double, value: Int) {
        self.sideLength = sideLength
        super.init(value: value)
        name = "xixi"
    }
    override func func10() -> String {
        print("lalala~")
        return name
    }
}




// 除了储存简单的属性之外,属性可以有getter和setter
class className3 {
    var sideLength: Double = 2
    var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }
}


var instanceName2 = className3()
print(instanceName2.perimeter)
instanceName2.perimeter = 8
print(instanceName2.sideLength)




// willSet和didSet 在设置一个新值之前或之后运行的代码
class className4 {
    var age: Int = 0 {
        willSet {
            print("we will set an new value \(newValue) to age")
        }
        didSet {
            print("we have changed \(oldValue) to \(age)")
        }
    }
}


var instanceName4 = className4()
instanceName4.age = 8
instanceName4.age = 12




// 使用enum创建枚举
enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
        default:
            return String(self.rawValue)
        
        }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue




// 使用struct创建结构体。结构体和类相似,比如方法和构造器。结构体是传值,类是传引用
struct Card {
    var rank = 1
    func func11() -> String {
        return "hello"
    }
}




// 使用protocol来声明协议
// mutating 关键字用来标记一个会修改结构体的方法
protocol ExampleProtocol {
    var value11: Int {get}
    mutating func adjust()
}
// 类、枚举和结构体都可以实现协议




// Extension 扩展是给已经存在的类,结构体,枚举类型和协议增加新的功能
// 扩展能够增加新功能,但是不能覆盖已有的功能




// 错误处理
// 定义错误类型:
enum PrinterError: Error {
    case OutOfPaper
    case NoToner
    case OnFire
}
// 使用throw关键字来抛出一个错误、使用throws关键字来表示一个可以抛出错误的函数。
// 如果在函数中抛出一个错误,这个函数会立刻返回并且调用该函数的代码进行错误处理
func send(job: Int, toPrinter printerName: String) throws -> String {
    if printerName == "Never Has Toner" {
        throw PrinterError.NoToner
    }
    return "Job sent"
}
// 在do-catch中进行错误处理,使用try标记抛出错误的代码
do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrinterError.OnFire {
    print("I'll just put this over here, with the rest of the fire")
} catch let printerError as PrinterError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}
// 错误处理的另一种方法:使用try? 将结果转换为可选的。如果函数抛出错误,该错误会被抛弃并且结果为nil。否则的话,结果会是一个包含函数返回值的可选值
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
// 使用defer代码块表示在函数返回之前,函数中最后会执行的代码




// 泛型




// 可以使用where对参数做出一些约束,比如必须是实现了某一个协议,或者说具有一个特定的父类