Swift 基础语法补充:
一.可选类型:
可选类型是swift的一大特色,在定义变量时,如果指定这个变量是可选的话,就是说这个变量可以有一个指定类型的值或者为nil。
? 和 ! 的区别
“?”表示可选类型(Optionals),“!”表示隐式可选类型,其实还是可选类型。
可选类型:将已存在的某种类型(结构体、枚举、类)定义为可选类型,表示该“新”类型的值可以为空nil
var nickName : String?
使用self.label!是明确声明此时self.label里一定有值,无论什么情况都调用后面的.text赋值方法。
而使用self.view?是声明此时并不确定self.view里是否有值,所以只在view有值时调用后面.addSubview方法。
这样做的目的一是让代码更明确, 二是给编译器提供更多线索,在编译时发现更多潜在错误。
1.定义一个optional 的常量:
let x:Optional = 10
print(x)
点击进去查看,可以发现Option其实是一个枚举类型。这个枚举有两个值,一个是none,表示没有值,而另一个是some,表示某一类值。
在输出的时候,可以看见控制台上的内容Optional(10),它的作用就是提示这是一个可选值。
而在实际开发中,一般不用上述方式创建可选值,而是指定一个类型,再在其后添一个问号。
let x:Optional = 10 //第一种写法
let x:Int? = 20 //第二种写法
print(x)
上述代码问号的意思就是定义一个可选的Int类型,可能没有值,也可能有一个整数。
2.解包:
试试将上面案例x和y相加,这个时候还能输出结果么?
此时可以看到编译器已经报错。在前面的教程中提到过,不同类型的值是不能直接运算的。而可选项若它的值为nil则不能参加计算。
因此引入解包的概念,“!”代表强制解包。它的意思是从可选值中强行获取对应的非空值。
输出结果:
3.解包常见错误:
//错误示范1
let y : Int?
print(y)
使用let定义的是常量,在初始化时必须要给出值。
//错误示范2:
let y : Int? = nil
print(y)
强制解包是危险操作,如果可选值为nil,强制解包系统会奔溃。
4.let 和 var的可选默认值:
//默认值测试
let x: Int?
print(x)
var y :Int?
print(y)
用let做测试时会直接报错,说明let的可选值是没有默认值的,而用var做测试时,报错信息就变成了警告,运行的结果为nil。可以由此推测出var的可选项默认值为nil。
swift中有规定,对象中的任何属性在创建对象时,都必须有明确的初始化值。
5.可选绑定:
用if let/var表示。它将变量赋值给一个临时变量,在这个操作中会做两步操作:首先判断变量是否有值,如果没有值,则直接不执行大括号里面的内容;如果有值,系统会自动将变量进行解包,并且将解包后的结果,赋值给临时变量。
//例如
通过一个字符串创建NSURL对象
let url: URL? = URL(string: "https://www.baidu.com")
接着创建NSURLRequest对象.
强制解包非常危险,当url有中文的时候可能会变成nil。所以要判断url是否为空再对其进行解包。
if let url = url {
let request = URLRequest(url: url)
}
二.If语句和三目运算符:
1>.if语句
在swift中,if语句是不用带小括号的,但是后面跟的语句必须有花括号,哪怕只有一行代码。
let a = 10
//if 条件句是没有小括号的
if a > 5 {
print("小仙女")
}else {
print("小鲜肉")
}
2>.三目运算:
三目运算符的写法是表达式后跟一个问号,用冒号来隔开条件是否成立的值。
let x = 10
x > 5 ? print("小仙女") : print("妖精") //注意swift语法比较严谨,空格也要注意
如果开发者只想处理条件成立的部分,此时可以在冒号后面用一个小括号来代替条件不成立的部分。
x > 5 ? print("你写了两次啦"):()
三目运算的简单模式:处理可选项
"??"的意思是说,如果表达式有值,就使用那个值,如果没有,就是呀“??”后面的值来代替
let x:Int? = nil
let y:Int? = 9
print((x ?? 0) + (y ?? 0))
运行之后结果为9
再说说运算符的优先级
let name:String? = "安琪拉"
print((name ?? "") + "火烧屁屁咯")
print(name ?? "" + "火烧屁屁咯")
/*
输出结果:
安琪拉火烧屁屁咯
安琪拉
*/
从运行的结果可以看到,“??”的优先级是最低的。如果没有小括号的约束,它会将后面的语句都当成是一个表达式。
if let 和 var 连用 (提高安全性,括号里面一定是有值的)
let oName:String? = "小小"
let oAge:Int? = 18
//方法1
if oName != nil && oAge != nil {
print(oName! + String(oAge!))
}
//方法2 let和var连用
if var name = oName , let age = oAge {
name = "哈哈"
print(name + String(age))
}else {
print("x 或 y的值为NIl")
}
三、Guard使用:
Guard里面是一定有值的
let oName:String? = "小小"
let oAge:Int? = 18
guard let name = oName , let age = oAge else {
print("姓名或者年龄是nil")
return
}
print(name + String(age))
四、Switch使用:
Swift中的Switch可以使用任意类型,而不限制是Int类型
//Swift中的Switch可以使用任意类型,而不限制是Int类型
//Swift中的Switch不需要break
//如果要使多个值等于相同的结果,直接用","逗号隔开
func demo(num:String) {
switch num {
case "10","9":
print("优秀~")
case "8":
break
default:
print("及格")
}
}
五、For循环:
数字和...之间不能加空格
//For循环
func demo() {
//大于0 小于5
for i in 0..<5 {
print(i)
}
//输出结果:0 1 2 3 4
print("----------------------")
//大于0 小于等于5
//数字和...之间不能加空格
for i in 0...5 {
print(i)
}
//输出结果:0 1 2 3 4 5
}
//逆序
//逆序
for i in (0..<10).reversed() {
print(i)
}
//输出结果:9 8 7 6 5 4 3 2 1 0
六、字符串:
由双引号包裹起来的文本字符集
func demo() {
//不可变字符串
let someString = "someString"
//可变字符串
var variableString = "Horse"
variableString += "and carriage"
print(someString + variableString)
//字符串初始化
var anotherEmptyString = String()
let emptyString = ""
//字符串判断是否为空
if emptyString.isEmpty {
print("Nothing !")
}
}
遍历字符串和计算文字长度:
//遍历字符串:
for character in "Dog!?".characters {
//print(character)
}
//计算文字的长度,每个汉字代表3个字节
let str = "Hello world 你好"
print(str.lengthOfBytes(using: String.Encoding.utf8))//计算字节的数量
print(str.characters.count)//字符的个数
七、数组:
//Set 无序不重复
//用于存储多个元素的集合,元素的类型必须一致,同时,Swift支持泛型集合
//集合的可变性取决于是常量和变量
①创建数组
//Array
//A:初始化方法
//Array<Element> : Element 是数组中唯一存在的指定类型 或者 [element]
var someInt = [Int]()//创建一个空数组 数组的值类型被推断为Int类型
someInt = [1,2,3]
print(someInt)//结果:[1, 2, 3]
var threeDoubles = Array(repeating: 1.2, count: 3)//repeating 后为数组默认值,count 为数组长度
print(threeDoubles[1]) //结果:1.2
//B:通过两个数组相加创建数组
let threeDoubles = Array(repeating: 0.0, count: 3)
let anotherDoubles = Array(repeating: 2.9, count: 2)
let result = threeDoubles + anotherDoubles
print(result)
//C: 字面量创建数组
var shoppingList :[String] = ["EGGS","MILK"]
var shoppingList2 = ["Eggs","Milk"]
②操作数组
//字面量创建数组
var shoppingList = ["Eggs","Milk"]
//转义斜杠 + () 格式化打印字符串 //isEmpty判断是否为0
print("一共有\(shoppingList.count)项")
//给数组添加新元素
shoppingList.append("Flour")
//第二种添加方法
shoppingList += ["cheese", "Butter"]//追加
//在具体索引值添加元素 insert
shoppingList.insert("Map", at: 3)
//替换指定元素
shoppingList[2...4] = ["替换2","替换3"]
//删除
shoppingList.remove(at: 0)
//删除最后一个
shoppingList.removeLast()
print(shoppingList)
//遍历
for i in shoppingList {
print(i)
}
//for
//enumerated
for (index,value) in shoppingList.enumerated() {
print(String(index+1)+(value))
}
print("--------------------------------------")
八、集合
①创建集合
//Set 无序不重复
//集合Set 形式:Set<Element>
//创建空的集合
var letters = Set<Character>()
print("Letters的集合长度为\(letters.count)")
//用数组字面量构造集合
//var favorite:Set<String> = ["Rock","Hip pop"]
var favorite:Set = ["Rock","Hip pop"]
//添加元素
favorite.insert("Jazz")
if let removeBack = favorite.remove("Rock") {
print(removeBack)
}else {
print("没有值")
}
//删除整个集合 removeAll
//遍历并排序
for item in favorite.sorted() {
//按照首字母输出
print("item-\(item)")
}
②操作集合 真子集,即子集不等于父集
func demo2() {
let oddD: Set = [1,3,5,7,9]
let evenD: Set = [0,2,4,6,8]
let singleDPrime: Set = [2,3,5,7]
print(oddD.union(evenD).sorted()) // 合并
//结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(oddD.intersection(evenD).sorted()) //相交
//结果:[]
print(oddD.subtracting(singleDPrime).sorted()) //取差值
//结果:[1, 9]
print(oddD.symmetricDifference(singleDPrime).sorted())//取两个集合不同
//结果:[1,2,9]
}
let houseAnimals:Set = ["?","?","?"]
let farmAnimals:Set = ["?","?","?","?","?","?"]
let cityAnimals:Set = ["?","?"]
print(houseAnimals.isSubset(of: farmAnimals))//判断前一个值是否包含在后面的集合 结果:true
print(farmAnimals.isSuperset(of: houseAnimals))//判断所有的值是否包含 结果:true
print(farmAnimals.isDisjoint(with: cityAnimals))//是否没有交集 结果:false (有交集)
九、字典
创建字典和操作字典:
//创建字典
var nameOfIntegers = [Int:String]() //创建一个空的字典
var someDict:[Int:String] = [1:"one",2:"two",3:"three"]//字面量方式创建
//获取值
let someVar = someDict[2]
print("key=1的值\(someVar!)")//输出结果为:two
//修改值
var oldVar = someDict.updateValue("one的新值", forKey: 1)
print("key=1的值\(oldVar!)")//oldVar 是旧值
someDict[2] = "two的新值"
print(someDict[1]!)
//操作字典
//移除
var removeValue = someDict.removeValue(forKey: 2)
print("key=2的值为\(removeValue!)")//输出结果为:key=2的值为two的新值
//someDict[3] = nil
//print(someDict) //输出结果:[1: "one的新值"]
//遍历字典
for (key,value) in someDict {
print("遍历字典key:\(key) value:\(value)")
}
for (key,value) in someDict.enumerated() {
print("遍历字典key:\(key) value:\(value)")//带索引
}
//字典转数组
let dictKeys = [Int](someDict.keys)
let dictValues = [String](someDict.values)
十.函数与闭包
//函数与闭包
//函数相当于Objective-C中的方法,是一段完成特定任务的独立代码片段。可以通过给函数命名来标志某个函数的功能。而这个名字可以用来在需要的时候“调用”该函数完成其任务。格式如下
func 函数名(参数列表)-> 返回值类型 {
代码块
return 返回值
}
func表示关键字,多个参数列表之间用逗号隔开,也可以没有参数。使用->指向返回值类型。如果没有返回值,可以用Void代替,也可以省略
//1、定义无参无返回的函数
func phone() -> Void {
print("小米")
}
//phone()
//2.定义无参,有返回值
func phoneNum() -> String {
return "123456"
}
//print(phoneNum())
//3.定义有参无返回值
func callPhone(phoneNum:String) -> Void {
print("打电话给\(phoneNum)")
}
//4.定义有参有返回的函数
func sum(num1 : Int , num2 : Int) -> Int {
return num1 + num2
}
//5.函数无返回值类型:
func demo() {
}
func demo1() -> () {
}
func demo2() -> Void {
}
//6._ 下划线的使用
func firstFunc(_ age1 : Int , _ age2 : Int) -> Int {
return age1 + age2
}
//在swift4之后,调用函数的时候,能直观的看到参数。而在之前调用之时,只能看见第二个参数之后的名称,表达起来并不直观。如何解决这个问题呢?
//可以采用给参数起别名的方式,在参数前面添加一个别名。
func getSum(number1 num1: Int,number2 num2 : Int) -> Int{
return num1 + num2
}
函数的默认值
//函数的默认值
func defaultFunc( name:String = "小Boss", age:String = "18") -> String {
return name + age
}
//print(defaultFunc()) //输出结果 小Boss18
//print(defaultFunc(name: "小明", age: "18")) //输出结果 小明18
//print(defaultFunc(name: "小仙女")) //输出结果 小仙女18
闭包:自包含的函数代码块
let f = sum //f 是把函数的指针记录下来
print(f(20,40))//结果:60
func sum(x:Int , y:Int) -> Int {
return x + y
}
//1.无参无返回值的闭包
let b1 = {
print("干掉他们")
}
b1()
//闭包格式 {形参列表 -> 返回值类型 in 实现代码}
//2.有参无返回值的闭包
let b2 = {
(x:String) -> () in print(x)
}
b2("String")
//3.带参数,带返回值的闭包
let b3 = {
(x:Int) -> Int in return x + 3
}
print(b3(4))//输出结果:7
尾随闭包和逃逸闭包:
override func viewDidLoad() {
super.viewDidLoad()
//普通调用
myFunc(strP: "Hello", closureP: {
(string) in print(string)
})
//尾随闭包调用
myFunc(strP: "Hello") {
(string) in print(string)
}
testEscaping {
[unowned self] () -> Void in
self.x = 100
}
print("x=\(x)")//输出结果为:x=10 没有被修改为100
callBackArray.first?()//修改了x
print("x=\(x)")//输出结果为:x=100 修改成功
}
//1.尾随闭包
func myFunc(strP:String,closureP:(String) -> Void) -> Void {
closureP(strP)
}
//2.逃逸闭包 在函数之后才能被调用 (闭包逃出了函数的作用域)
var x = 10
var callBackArray:[()->Void] = [] //定义数组,数组的元素都是闭包类型的
//@escaping 允许逃逸出函数
//逃逸闭包的方法
func testEscaping(callBack:@escaping () -> Void) {
callBackArray.append(callBack)
}