美文网首页
Swift 学习2

Swift 学习2

作者: Taureau_2d81 | 来源:发表于2017-06-10 17:32 被阅读0次

    一:playground

    作用:学习代码、实验代码、测试代码

    官方的学习资源是以playgroud形式提供的,建立自己的playgroud文件,能够每次版本升级时,第一时间发现语法的变化

    Swift程序中与Oc的不同

    1、没有.h与.m文件,都是以.swift结尾的文件

    2、没有main.m文件 —— appDelegate中的@UIApplicationMain 就是程序的入口

    3、Swift的类都是用class标识

    4、OC中的initwithXX方法在Swift中是“类型(xxx)”

    5、swift中的属性和方法都是用 “.” 的形式

    6、结尾可以不加分号(加了也可以)

    7、在当前类中使用当前属性,不需要加“self."(除了闭包)

    8、在swift中把枚举分成了两部分"枚举名.枚举值",枚举名可以省略

    9、在swift中使用print打印,也可以使用nslog,但效率没有print高


    二、Swift的基本语法

    1、变量与常量

    swift中变量与常量的类型可以不设置,在赋值时由系统自动推断,如果希望手动指定那么在变量或常量后加":类型"

    在swift中,不同类型之间不能进行运算,oc可以,因为oc有隐式转换

    运算符对称,运算符左右两边的空格要对称,如果一边有空格,另一边没有就会报错,一边多了个空格不会报错,但影响美观

    var来声明变量。在swift中,如果定义了一个变量,没有初始值的时候,系统会报错。如果开发者就是想声明一个变量为空,那么需要在类型的后面加个"?"

    let用来声明常量。在swift中,如果定义了一个常量,没有初始值的时候,系统会报错。对于常量,不能通过后面加"?"来处理,只能赋值为nil或者0来处理。


    2、if判断与guard判断

    在swift中没有  非零即真  的概念,条件语句一定是bool类型(true/false )

    swift中条件语句的小括号可以省略,但如果执行代码只有一句,代码块的大括号不可以省略

    guard判断如果条件不成立,那么执行else代码块,相当于一个没有第一个代码块的if


    3、三目运算 与 可选类型

    三目运算在swift中与oc没有区别

    在可选类型中,"??" 是一个简单的三目运算,比如

    age ?? 0   意为age为nil或空时使用??后面的0值

    使用 ? 修饰的类型为可选类型,属性在赋值时候,会带有Optional关键字,这样不能与不带关键字的类型做操作,可以使用 "!"来强行解包,但使用需要小心小心再小心。


    4、if  _ let  /   guard    _  let   

    类似自定义view的if(self =  [super   XXX])中的  “=”,判断等号前面的有值就执行第一代码块,否则else。声明的作用域仅仅在if内部。

    而guard是判断不成立则执行else,声明作用域为guard的下方(不仅仅在guard内部)


    5、for循环

    不可以使用c形式的for循环,++形式在swift3.0后移除不能在使用,for循环的时候,小括号不要写

    语法:

    for    i       in        x..<y    (x ---- y-1)

    for    i        in       x...y       (x-------y)

    for    value   in  arr            (arr 数组)


    6、switch

    swift的switch可以判断任何类型,比oc要广;

    默认没有break,并且不会造成穿透效果(如果想实现穿透,设置关键字 "fallthrough");

    switch可以进行范围判断           语法:

    case     _where   c(声明的变量) > 60 (范围)


    7、字符串的长度、遍历、截取、拼接

    在swift中字符串可以直接使用String表示,string本质是一个结构体,比oc的NSSting更加轻便,而且效率更高。

    问题:

    ——如何获取字符串长度

         ——str.characters.count

    ——如何遍历字符串

         ——for char   in  str.characters   其中char就是一个字符

    ——字符串字节注意点

        ——一个英文/数字等于一个字节,一个中文等于三个字节

    ——字符串截取

         ——如一字符串"123456789"

            ~  最后两个不要  let  end2index = str.index(str.endIndex, offsetBy: - 2)

               str.substring(to: end2index)

            ~  前两个不要  let  start2index = str.index(str.start, offsetBy: 2)

            str.substring(from: end2index)

            ~  如何把string转化成NSString

            使用as 相当于强转

    ——字符串如何拼接

        ——需求:两个常量 "老王"  18,拼接成"我叫老王今年18"

             ~方式1

               ~  "我叫" + name + "今年" + string(age)

           ~方式2

                ~"我叫\(name)今年\(age)"    **常用


    8、数组定义、拼接、遍历

    ——数组定义

    ——使用中括号形式,如果数组中有不同类型,需指定一下 ":[Any]"

    ——如何定义可变和不可变的数组

    ——可变数组用var    不可变的就是let

    ——如何合并数组

    ——"+="  arr  +=  arrb;

    ——如何往数组添加元素

    ——"append"

    ——如何移除元素

    ——"remove"系列

    ——如何获取元素

    ——和oc一样通过下标


    9、函数

    无参无返、有参无返,有参有返、外部参数

    无返回值的三种写法

    方法一

    func  demo (){

    }

    方法二

    func  demo () -> Void{

    }

    方法三

    func  demo () -> (){

    }

    ——函数类型作为参数

    你可以用(Int, Int) -> Int这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现留给函数的调用者来提供。

    下面是另一个例子,正如上面的函数一样,同样是输出某种数学运算结果:

    func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {

    print("Result: \(mathFunction(a, b))")

    }

    printMathResult(addTwoInts, 3, 5)

    // 打印 "Result: 8"

    ——函数类型作为返回类型

    你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->)后写一个完整的函数类型。

    下面的这个例子中定义了两个简单函数,这两个函数的类型都是(Int) -> Int:

    func stepForward(_ input: Int) -> Int {

    return input + 1

    }

    func stepBackward(_ input: Int) -> Int {

    return input - 1

    }

    如下名为chooseStepFunction(backward:)的函数,它的返回类型是(Int) -> Int类型的函数。

    func chooseStepFunction(backward: Bool) -> (Int) -> Int {

    return backward ? stepBackward : stepForward

    }

    ——函数内部定义函数(嵌套函数)

    默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。

    func chooseStepFunction(backward: Bool) -> (Int) -> Int {

               func stepForward(input: Int) -> Int { return input + 1 }

                func stepBackward(input: Int) -> Int { return input - 1 }

                return backward ? stepBackward : stepForward

    }

    var currentValue = -4

    let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

    // moveNearerToZero now refers to the nested stepForward() function

    while currentValue != 0 {

               print("\(currentValue)... ")

               currentValue = moveNearerToZero(currentValue)

    }

    print("zero!")

    // -4...

    // -3...

    // -2...

    // -1...

    // zero!


    10、block 闭包

    ——基本的闭包形式

    block一般用在  异步任务完成的回调

    无参无返回

    方法一

    let   demo  = {

    }

    方法二

    let  demo  = { () in

    }

    方法三

    let  demo  = { () ->Void  in

    }

    方法四

    let  demo  = { () -> () in

    }

    有参数无返回

    let  demo =  { (a: Int, b:Int) in

    }

    有参数有返回

    let  demo =  { (a: Int, b:Int)  -> Int in

    }

    解析:in后面写具体希望执行的代码,in前面为  有参无返/有参有返  的定义

    ——尾随闭包

    ——若将闭包作为函数最后一个参数,可以省略参数标签,然后将闭包表达式写在函数调用括号后面

    func testFunction(testBlock: ()->Void){

    //这里需要传进来的闭包类型是无参数和无返回值的

    testBlock()

    }

    //正常写法

    testFunction(testBlock: {

    print("正常写法")

    })

    单表达式闭包隐式返回

    reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )

    根据上下文推断类型

    reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

    单行表达式闭包可以通过省略return关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:

    reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

    在这个例子中,sorted(by:)方法的参数类型明确了闭包必须返回一个Bool类型值。因为闭包函数体只包含了一个单一表达式(s1 > s2),该表达式返回Bool类型值,因此这里没有歧义,return关键字可以省略。

    1、如果有多个参数,最后一个参数为闭包,(这是才称为尾随闭包)那么尾随闭包就会提前把小括号关闭

    //尾随闭包写法

    testFunction(){

    print("尾随闭包写法")

    }

    2、当只有一个参数且为闭包时,那么尾随闭包就会把小括号和参数省略

    //也可以把括号去掉,也是尾随闭包写法。推荐写法

    testFunction {

    print("去掉括号的尾随闭包写法")

    }

    ——逃逸闭包

    当一个闭包作为参数传到一个函数中,需要这个闭包在函数返回之后才被执行,我们就称该闭包从函数种逃逸。一般如果闭包在函数体内涉及到异步操作,但函数却是很快就会执行完毕并返回的,闭包必须要逃逸掉,以便异步操作的回调。

    逃逸闭包一般用于异步函数的回调,比如网络请求成功的回调和失败的回调。语法:在函数的闭包行参前加关键字“@escaping”。

    //例1

    func doSomething(some: @escaping () -> Void){

    //延时操作,注意这里的单位是秒

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {

    //1秒后操作

    some()

    }

    print("函数体")

    }

    doSomething {

    print("逃逸闭包")

    }

    //例2

    varcomletionHandle: ()->String = {"约吗?"}

    func doSomething2(some: @escaping ()->String){

    comletionHandle = some

    }

    doSomething2 {

    return"叔叔,我们不约"

    }

    print(comletionHandle())

    //将一个闭包标记为@escaping意味着你必须在闭包中显式的引用self。

    //其实@escaping和self都是在提醒你,这是一个逃逸闭包,

    //别误操作导致了循环引用!而非逃逸包可以隐式引用self。

    ——闭包的循环引用及解决方法

          ——原因

            ——原理跟OC中的block类似, 当有个属性记录下了函数传递回来的闭包, 产生强引用, 就会发生闭包的循环引用 

            ——解决方法(三种)

              ——使用weak修饰变量, 打破强引用, 因为使用weak修饰的变量有一次变成nil的机会

              ——使用[weak self] 修饰闭包原理跟__weak类似, 这样在闭包中使用self, 就是弱引用

             ——使用[unowned self ] 修饰闭包, 跟__unsafe_unretained类似, 不安全

    11、面向对象

    在一个模型类中,属性用var而不是let。

    创建Person对象时,可以直接使用    "类名()"的形式

    声明常量或者变量时候,默认应该是有值的。

              解决方案

               方法一

              把属性变为可选类型(一般使用这种)

              方法二

              直接赋值

             方法三

            在构造函数中赋值,(需要写在super之前)

    ——重写与重载构造函数

        ——重写

         父类方法,子类再写一遍

        ——重载

         都是在一个类中,方法名相同,参数不同

         好处:更灵活,方便记忆,只需要记住方法名即可


    12、异常处理

    所有的方法后带有throws的都应该进行错误处理

    写法为     在所需执行的代码前面写      "try/try?/try!"   (其中try与try?比较常用)

    方式1   try

    使用默认的try时,如果有错误可以通过do—catch进行捕捉,如果没有错误,那就正常执行

    do{

           let   res = try   JSONSerialization.jsonObject(with:data,options:[])

           print()

    }catch{

          print()

    }

    方式2  try?

    try?如果使用的是可选try,那么如果有错误会返回nil,没有错误就会正常执行

    let  res = try  JSONSerialization.jsonObject(with:data,options:[])

    print()

    方式3  try!

    try!是强行try,意思是可以放心的用,但是如果是错误的,那么就崩溃了

    相关文章

      网友评论

          本文标题:Swift 学习2

          本文链接:https://www.haomeiwen.com/subject/xpfcqxtx.html