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)



swift ISO 20022_数组

点击进去查看,可以发现Option其实是一个枚举类型。这个枚举有两个值,一个是none,表示没有值,而另一个是some,表示某一类值。

在输出的时候,可以看见控制台上的内容Optional(10),它的作用就是提示这是一个可选值。

而在实际开发中,一般不用上述方式创建可选值,而是指定一个类型,再在其后添一个问号。



let x:Optional = 10  //第一种写法
let x:Int? = 20     //第二种写法
print(x)



上述代码问号的意思就是定义一个可选的Int类型,可能没有值,也可能有一个整数

2.解包

试试将上面案例x和y相加,这个时候还能输出结果么?

swift ISO 20022_解包_02

此时可以看到编译器已经报错。在前面的教程中提到过,不同类型的值是不能直接运算的。而可选项若它的值为nil则不能参加计算。

因此引入解包的概念,“!”代表强制解包。它的意思是从可选值中强行获取对应的非空值。

swift ISO 20022_移动开发_03

输出结果:

swift ISO 20022_swift_04

3.解包常见错误

 



//错误示范1
let y : Int?
print(y)



swift ISO 20022_移动开发_05

使用let定义的是常量,在初始化时必须要给出值。



//错误示范2:
let y : Int? = nil
print(y)



swift ISO 20022_数组_06

强制解包是危险操作,如果可选值为nil,强制解包系统会奔溃。

4.let 和 var的可选默认值



//默认值测试
let x: Int?
print(x)
var y :Int?
print(y)



swift ISO 20022_swift ISO 20022_07

用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循环:

数字和...之间不能加空格

swift ISO 20022_移动开发_08



//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)
    }