Swift基础学习(一)

今天系统的总结一下swift的语法,方便后期查看。

本篇学习总结:

  • 常量和变量
  • 变量和常量的输出
  • 类型安全和类型推导
  • 基本运算
  • 区间运算符
  • 逻辑分支(if, guard, switch)
  • 循环语句(for, while,repeat while)
  • 集合(Array, Dictionary, Set,元组)
  • 可选类型
  • 类型转换

好了,带着知识点,我们一一开始阅读吧

常量和变量

Swift中定义标识符必须明确指明该标识符是常量还是变量。常量和变量将名字(标识符)和一个特定类型的值关联起来。

使用let定义变量,表示该值不能更改
使用var定义变量,表示该值可以更改

语法格式:

// let / var 标识符名称 : 标识符类型 = 赋值
let score : Double = 89.5
var age : Int = 20
// Swift中如果一行只有一条语句的时候,那么语句结束时的;可以省略

注意点:

  • 1.在开发中,我们一般优先使用常量,只有发现标识符需要修改时,在使用变量,这样做防止我们在不希望它值修改的情况下,在其他地方被修改。
  • 2.常量的本质:标识符指向的内存地址不可以被修改,但是可以通过内存地址找到对应的对象,修改对象内部的属性。
  • 3.省略:上面的例子中:Double 和 :Int是可以省略的,事实上,我们也不需要经常使用类型标注,如果在定义一个变量或常量的时候就初始化一个值,那么Swift九江推断出这个变量或常量的类型,可以通过option + 鼠标左键来查看标识符类型
  • 4.标识符名称,也就是变量和常量的名字不能包含空白字符,数学符号,箭头,保留的或者无效的Unicode码位,连线,制表符,也不能以数字开头。

变量和常量的输出

Swift中使用print()打印变量和常量中的值

print("hello swift")
// 当需要输出变量或常量的时候,可以直接使用字符串插值的方式把变量名或常量名当做占位符加入到字符串当中,Swift会用常量或变量的当前值来替换这些占位符
// 通过将常量或变量放入()中并在前面加上\将其转义
let version : Double = 4.0
print("hello swift \(version)")

类型安全和类型推导

Swift是一门类型安全的语言,类型安全的语言可以让我们清楚的知道值的类型,帮助我们规避很多错误。Swift会在编译代码的时候进行类型检查,如果我们错误的将不匹配的类型进行附值,编译器会报错。
同理,如果没有为值进行类型说明,Swift会通过检查我们给变量赋的值并在编译阶段会自动推断出附值的合适类型,这个过程就是类型推导。

我们可以通过option + 鼠标左键查看标识符类型。

let score  = 89.5
var age  = 20
// 编译器会在赋值时自动根据其值推断出 score为Double类型,age为Int类型
let sum = 55.5 + 30
// 甚至编译器会推断出算式的值得类型为Double

基本运算

Swift中相同类型的数据之间才可以进行运算,Swift中没有类似OC中的隐式类型转换,所以当两个变量类型不同时,需要进行强制类型转换,前面提到过Swift时一门强类型语言,即使Int8类型和Int类型也不能直接进行运算,同样需要强制转换类型才可以。

强制类型转换 Int(标识符a),Double(标识符b)

let n = 10
let x : Int8 = 5
let m = 10.5

let result = Double(n) + m // Int转化为Double
let result1 = Int(m) + n // Double转化为Int
let retule2 = Int(x) + n // Int8 与 Int进行运算同样需要转化

除了不同类型之间运算需要进行强制类型转换外,Swift中其他基本运算符与OC中一样,Swift中还添加了一些非常方便的元素符.

区间运算符

  1. 闭区间运算符(a...b),定义了从a到b的一组范围,并且包含a和b,要求a <= b.
  2. 半开区间运算符(a..,定义了从a到b 但不包括b的区间,要求a <= b,当a=b时那么返回的区间为空.
  3. 单侧区间运算符[2...],一般用于数组中,例如list[2...] 即表示从list数组索引2开始一直到结束,注意这时2必须小于数据的count,否则编译器将会报错.
  4. 当然也可以写成[...2]表示从0开始到2的索引,[..<2]表示从0开始到1的索引.

逻辑分支

Swift提供了多种多样的控制流语句,是我们在日常使用中可以根据不同的情况进行使用,除了if while之外Swift 还提供了guard语句来应对需要对多个条件进行判断的情况,是代码逻辑显得更加清晰。

if 条件语句

Swift中的if条件语句后面的()内容可以省略,同事需要注意的是,Swift中没有像OC中的非0(nil)即真的判断方式,也就是说Swift中我们必须给出明确的判断条件.

let score = 88

if score > 0 {
    print("score > 0")
}
if score != 0 {
    print("score != 0")
}
// 这里不能像OC中 if (a) {} 即可判断a是否为0,Swift中必须给出明确的判断条件

if条件判断语句同OC中一样,只不过if后面()去掉也许会让我们稍有些不习惯,不过很快就会熟悉

// if else
if score < 0 || score > 100 {
    print("不合理分数")
}else if score < 60 {
    print("不及格")
}else if score >= 60{
    print("及格")
}

guard条件语句

guard 的使用与if非常相似,可以同if进行无缝转化,为了提高代码的可读性,我们可以把guard看作一个看门人,不符合条件的统统不许通过,最后通过的也就是我们想要的结果

let idCard = true
let ticket = true

func Ontrain (idCard : Bool , ticket : Bool) {
    // 判断有没有带身份证
    guard idCard else {
        print("没有带身份证,不可以乘车")
        return
    }
    // 判断有没有车票
    guard ticket else {
        print("没有车票,不可以乘车")
        return
    }
    
    print("身份证和车票都带了,可以乘车")
    // 满足以上所有条件才可以 使用场景:满足所有条件才可以达成某些功能
}

Switch语句

  1. switch后面的()可以省略.
  2. case语句结束,可以不加break,系统默认帮我们加上了break,如果希望case结束时产生穿透,去除break效果需要加上fallthrough.
  3. 在每条case中必须包含至少一条可执行语句,不能为空.
  4. case语句后面可以判断多个条件。每个条件之间用逗号隔开,如果任何一个条件匹配了,则会执行case下的语句.
  5. switch可以判断多种类型,包括浮点型,字符串类型,区间类型,元祖
  6. switch可以将匹配到的值临时绑定为一个变量或者一个常量,来给case中的执行语句使用
  7. 同时可以在case语句后添加额外的where判断
  8. switch 可以被打伤标签循环使用

switch 基本使用

let sex = 0
switch sex {
case 0:
    print("M")
    break // 可省略
case 1:
    print("F")
    fallthrough // 如果想要产生穿透
default:
    print("?")
}

switch语句后面判断多个条件

switch sex {
case 0,1: // 任何一个条件匹配了,就会执行case下的语句
    print("正常")
default:
    print("???")
}

case进行区间匹配

let score = 88
switch score {
case 0..<60:
    print("不及格")
case 60..<80:
    print("及格")
case 80...100:
    print("优秀")
default:
    print("不合理分数")
}

switch中也可以判断多种类型,字符串类型,元祖,浮点型

// 这里用元组举例
let point = (1,1) // 类型为(Int,Int)的元组
switch point {
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0): // 如果不想匹配元组中的某一个值,可以用_代替
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2): // 元组中使用区间匹配
    print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// prints "(1, 1) is inside the box"

switch可以将匹配到的值临时绑定为一个变量或者一个常量,来给case中的执行语句使用

let personInfo = (name : "abc" , age : 20)

switch personInfo {
case (let x , 1..<18):
    print("未成年的人有\(x)")
case (let x , 18..<100):
    print("成年的人有\(x)")
default:
    print("没有匹配的人")
}
// print 成年的人有abc

switch 在case语句后面添加额外的where判断

let personInfo = (name : "abc" , age : 20)

switch personInfo {
case (let x , 1..<18) where x == "abc": // 只是举例,并没有意义
    print("未成年的人有\(x)")
case (let x , 18..<40) where x == "and":  // 只是举例,并没有意义
    print("成年的人有\(x)")
default:
    print("没有匹配的人")
}
// print "没有匹配的人\n"

给语句打标签

var times = 0
timeLoop : while times < 10 {
    times += 1
    switch times {
    case 6:
        break timeLoop
    case 4:
        continue timeLoop
    default:
        print("default")
    }
}
// print :  default default default default
// 这里我们给while循环打上timeLoop标签,可以发现,times等于1...3时打印了三遍defult,当times等于4时,continue结束了当前while循环并开始下一次循环,times等于5然后打印第四遍default,times等于6时bread timeLoop结束了while循环不在进行打印。

循环语句

swift中循环语句与OC中的相同,for,while,repeat while 循环,使用方法也与OC中基本相同

for i in 0..<10 {
    print(i)
}

// 在 Swift中如果一个变量/常量暂时不会使用,那么可以使用_来代替,_不会占用内存空间
for _ in 0...10 {
    print("hello Swift")
}

repeat while 也就是OC中的do while循环

var m = 0

while m < 10 {
    m += 1
    print(m)
}

// repeat 无论是否成立都要先走一次
repeat {
   m -= 1
    print(m)
} while m > 0

集合

1.Swift提供了三种主要的集合类型,所谓的数组,合集还有字典,用来存储值的集合。
数组:是有序的值的集合
合集:是唯一值的无序集合
字典:是无序的键值对集合
2.Swift中的集合都是泛型集合,也就是说集合需要明确存储的值的类型,保证我们不会意外的插入一个错误类型的值到集合中去,同时保证我们可以从集合中取回确定类型的值

Swift中的集合.png

数组

数组以有序的方式储存相同类型的值,相同类型的值可以在数组的不同地方多次出现。Swift中的数组是Array类型的,不像OC中区分NSArray 和 NSMutableArray,而是通过我们创建的不同来定义数组

不可变数组:let修饰
可变数组:var修饰

定义数组语法

// Array类型 <>里表示数组中存放的数据类型
let array : Array = ["a","b","c"] // 不可变数组不可操作
// 数组类型简写 推荐使用简写写法,更加简单清晰
let array : [String] = ["a","b","c"]
// 创建空数组
var arrayM2 = Array()
// 同样可以进行简写
var arrayM : [String] =  Array()
var arrayM1 = [String]()

/* 
* 同时数组还为我们提供了初始化方法创建
* repeating:表示数组存储对应类型的默认值
* count:表示数组内元素的个数
*/
var arr = Array(repeating: "a", count: 5)

对可变数组的基本操作

// 获取数组元素个数
let count = arrayM.count
// 同时也可以使用isEmpty Bool值属性 来对数组是否为空进行快速判断
if arrayM.isEmpty {
}

// 1. 添加元素
arrayM.append("abc")
// 也可以使用 +=运算符在数组末尾添加新的同类型元素
arrayM += ["aa","bb"]
// 使用 insert方法添加元素到指定位置
arrayM.insert("js", at: 1)

// 删除元素
arrayM.remove(at: 0) // 返回被删除的元素
arrayM.removeAll() // 删除所有的
arrayM.removeLast() // 删除最后一个
arrayM.removeFirst() // 删除第一个

// 提取元素
let name = arrayM[0]

// 修改元素
arrayM[0] = "abc"
// 也可以使用区间类型修改多个元素
arrayM[2...3] = ["haha","xixi"]

需要注意的是,同OC一样,当我们访问或者修改一个超出数组元素个数的值将会引发crash.

数组的遍历
同OC一样,我们可以使用for in来遍历整个数组中的值

for item in arrayM {
    print(item)
}
// 如果我们想要拿到数组中每个元组的值以及它的索引,我们可以使用enumerated()方法来返回数组中每一个元素的元组,元组中包含了元素的索引和值
for (index , item) in arrayM.enumerated(){
    print(index)
    print(item)
}

集合

Swift中集合的类型是Set,同OC中的NSSet一样,集合还将同一类型也不重复的值无序的存储在一个集合当中

定义集合语法

// 使用 Set创建并初始化一个集合
var letters = Set()
// 注意Set没有同数组一样对应的简写方式
// 也可以通过数组来创建集合
var name: Set = ["aa", "bb", "aabb"]

集合的访问与修改

// 通过count来访问集合内元素的个数
print(name.count)
// 也可以通过 isEmpty快速判断count属性是否为0
if name.isEmpty {
    print("As far as music goes, I'm not picky.")
}

// 通过insert为集合新增加一个元素
name.insert("enen")

// 删除集合中的元素
if let nameInfo = name.remove("bb") {
    print("\(nameInfo)")
}
// 如果集合中有bb这个元素那么就删除它,并且返回被删除的元素,如果没有就返回nil
// 我们这里使用 if let 来对返回的值进行判断,如果集合中存在被删除的参数,那么返回值不为nil,然后就会执行大括号里面的内容,如果集合中不存在该参数,那么就会返回nil,大括号中的内容就不会执行

// 使用contains()方法检查集合中是否包含了特定的元素
if name.contains("aa") {
    print("aa is in set")
}

集合的遍历

for nameStr in name {
    print("\(nameStr)")
}

// 可以通过使用 sorted方法将合集的元素进行排序
for nameStr in name..sorted() {
    print("\(nameStr)")
}

集合基本操作

Swift提供了很多便捷的方式让我们对集合进行基本操作来获取两个集合相交的集合或者其他等等。

  1. 使用intersection(_:)方法来创建一个只包含两个集合共有值的新集合。
  2. 使用symmetricDifference(_:)方法来创建一个只包含两个集合各自有的非共有值的新集合。
  3. 使用union(_:)方法来创建一个包含两个集合所有值的集合
  4. 使用subtracting(_:)方法来创建一个两个集合当中不包含某个集合值的新合集
  5. 使用相等运算符(==)来判断两个集合是否包含有相同的值
  6. 使用isSubset(of:)方法来确定一个集合的所有值是否被某合集包含
  7. 使用isSuperset(of:)方法来确定一个集合是否包含某个合集的所有值
  8. 使用isStrictSubset(of:)或者isStrictSuperset(of:)方法来确定某集合是否为另一个集合的子集或者超集,但并不相等
  9. 使用isDisjoint(with:)方法来判断两个集合是否拥有完全不同的值

示例如下:


前四种集合基本操作图例.png

字典

Swift中字典的类型是Dictionary,同样是泛型集合,Int Double类型均为结构体,都可以放入数组和字典中

字典的定义

let 定义不可变字典
var定义可变字典

// 字典也用[]表示,编译器会自动区分[]中是一个个元素(数组)还是键值对(字典)
let dic : Dictionary = ["string" : "aa", "age" : 18 , "height" : 1.88]
// 与数组一样,同样可以对字典进行简写
let dic2 : [String : Any] = ["string" : "aa", "age" : 18 , "height" : 1.88] // 推荐 这种写法更简便一些

//定义可变字典 var 修饰
var dicM = Dictionary  ()
var dicM1 = [String : Any]()

// 与数组一样,如果你用一致类型的字典字面量初始化字典,就不需要写出字典的类型了
var dicName = ["key1":"bb","key2":"dd"]

字典的基本操作

// 同数组一样字典也拥有count属性和isEmpty属性来得到字典的元素个数和快速判断字典元素个数是否为0

给字典添加元素
dicM["name"] = "abc"
dicM["age"] = 18
dicM["height"] = 1.88

// 删除元素
dicM.removeValue(forKey: "name") // 如果删除成功则返回被删除的值,如果字典没有这个键值对则返回nil
dicM.removeAll() 
// 我们也可以使用下标脚本语法给一个键赋值 nil来从字典当中移除一个键值对
dicM["name"] = nil

// 修改元素 字典会自动索引字典中没有相同的key,如果没有就添加,如果有就修改其值
dicM["name"] = "aa"
// updateValue的功能同上,同样会增加或修改元素的值
// 如果updateValue是更新已经存在键的值,则会返回原来旧值的可选类型
// 如果updateValue为字典新增加了一个元素,则返回nil
dicM.updateValue("aa", forKey: "name")

遍历字典

// 遍历字典中所有的key
for key in dic.keys {
    print(key)
}
// 遍历字典中所有的value
for value in dic.values {
    print(value)
}
// 遍历字典中所有的key - value
for (key,value) in dic{
    print(key, value)
}
// 拿到所有key 或value组成的数组
let keyArr = [String](dict.keys)
let valueArr = [String](dict.values)

// 我们可以通过遍历其中一个字典,为第二个字典赋值,来合并两个字典
let dicStr : [String : Any] = ["name" : "cl" , "age" : 18]
var dicStr2 : [String : Any] = ["name":"aa","height" : 1.88 , "phone" : "110"]
for (key , value) in dicStr {
    dicStr2[key] = value
}

同样,Swift的Dictionary类型是无序的,要以特定的顺序遍历字典的键或值,则需要使用sorted()方法。

元组

元组是Swift中新添加的可以将多个值合并成单一的复合型的值,并且元组内的值可以是任何类型,且不必是同一类型。任何类型的排列都可以被用来创建一个元组,它可以包括任意多的类型,元组非常方便的帮助我们解决了数组和字典的缺陷

元组的创建

// 元组创建写法一
let tuple = ("aaa",18,1.88)
// 可以通过从零开始的索引访问元组中的单独元素
let tupleName = tuple.0

// 写法二 为元组中单个元素命名
let tuple1 = (name:"aaa", age:18, height:1.88)
let nameLength = tuple1.name.characters.count
// 如果只想取出元组中部分数据,不想要取出的可以用_代替
let (tupleName2, age2, _) = tuple1
print("我叫\(tupleName2)今年\(age2)")

// 写法三 一一对应
let (name,age,height) = ("cl",18,1.88)
print(name)

可选类型

Swift中只有可选类型才能被附值为nil,其他类型都不能附值为nil
OC中当一个值不在使用时,我们可以将它附值为0(基本数据类型)或者附值为nil(对象类型),但是在Swift中,nil时一个特殊的类型,同String,Int相同。而Swift时一门强类型语言,类型不匹配无法附值,所以只有可选类型才能被附值为nil,被可选类型修饰的值则表示该值有可能为nil,被可选类型修饰的值则表示该值有可能为nil。

可选类型的定义

// 首先我们尝试给String变量赋值为nil编译器报错
// Nil cannot initialize specified type 'String'
// var name : String = nil

// 定义可选类型 Optional表示可选类型 泛型集合
var name : Optional = nil
// 简写 String?表示可选类型的string 
var name1 : String? = nil
// 问号明确了它储存的值是一个可选项,意思就是说它可能包含某些 String  值,或者为nil。

// 给可选类型进行赋值
name1 = Optional("aaa") // 方式一
name1 = "aaa" // 方式二 编译器会自动加上 Optional()

我们通过option查看name为String?可选类型


可选类型String?.png

同时当我们在类中创建暂时不需要使用的变量的时候,定义为可选类型并且不提供默认值,变量会被自动设置为nil.

对可选类型进行取值

print(name1)
// 取出可选类型中的值 可选类型! --> 强制解包
print(name1!)
// print  Optional("aaa")
// print  aaa

可以发现直接打印name1输出Optional("aaa")可选类型,并不是我们想要拿到的字符串,使用!对可选类型进行强制解包,可以拿到可选类型中的值,
我们只有非常确定可选类型有值才可以进行强制解包,一旦可选类型为nil,强制解包程序就会立即crash。

所以我们可以在使用的时候优先对可选类型进行判断

// 判断可选类型不为nil,然后才强制解包
if name1 != nil {
    print(name1!)
}

但是我们在开发中会大量的使用可选类型,如果每一个都需要进行判断就会非常麻烦,所以Swift推出可选绑定语法,该语法用于可选类型,是我们使用可选类型更加方便。

可选绑定语法

if let tempName = name1 {
    print(tempName)
}

可选绑定会优先判断name1是否有值,如果没有值,则直接不执行{}中的内容,如果name有值,那么系统会自动对可选类型进行解包,并且将解包后的结果附值给前面的tempName。

同时为了方便,并且避免同一个变量有多个名字,我们可以使用相同的名字进行命名,在大括号内直接使用相同的变量名即可。

if let name1 = name1{
    print(name1)
}

类型转换

我们通过as 将实例转化为一种类型

将String转化为NSString
let str = "askkdsfjksdfffff" as NSString
str.substring(to: 6)

通过as?将实例转化为可选类型

let dict : [String : Any] = ["name":"aaa" , "age" :18]
let tempName = dict["name"]
print(tempName!)
// 通过as?转成可选类型 这里将 any 类型 转成 string类型
// as? 转成的类型是一个可选类型,系统会自动判断tempName是否可以转成String类型,如果可以转成,那么获取字符串,如果转化不成功,则返回nil
let name = tempName as? String
if let name = name {
    print(name)
}
if let name = dict["name"] as? String {
    print(name)
}

通过as!转成具体类型

// 注意:如果转化不成功则程序会崩溃
// 建议:如果确定转化成功再用as! 进行转化
let tempName1 =  dict["name"]
let name1 = tempName1 as! String

使用as?转化的name为String?类型,使用as!转化为name1为String类型,可选类型不仅增加了代码的可读性,并且使Swift代码更加严谨和安全。

本篇先记录这些,如有错误,不吝赐教!

你可能感兴趣的:(Swift基础学习(一))