Swift 学习2

2017-06-10  本文已影响0人  Taureau_2d81

一: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,意思是可以放心的用,但是如果是错误的,那么就崩溃了

上一篇下一篇

猜你喜欢

热点阅读