一: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.. for i in x...y (x-------y) for value in arr (arr 数组) swift的switch可以判断任何类型,比oc要广; 默认没有break,并且不会造成穿透效果(如果想实现穿透,设置关键字 "fallthrough"); switch可以进行范围判断 语法: case _where c(声明的变量) > 60 (范围) 在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)" **常用 ——使用中括号形式,如果数组中有不同类型,需指定一下 ":[Any]" ——可变数组用var 不可变的就是let ——"+=" arr += arrb; ——"append" ——"remove"系列 ——和oc一样通过下标 无返回值的三种写法 方法一 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" 你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->)后写一个完整的函数类型。 func stepForward(_ input: Int) -> Int { return input + 1 } func stepBackward(_ input: Int) -> Int { return input - 1 } func chooseStepFunction(backward: Bool) -> (Int) -> Int { return backward ? stepBackward : stepForward } 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! 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关键字可以省略。 //尾随闭包写法 testFunction(){ print("尾随闭包写法") } //也可以把括号去掉,也是尾随闭包写法。推荐写法 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类似, 不安全 在一个模型类中,属性用var而不是let。 创建Person对象时,可以直接使用 "类名()"的形式 声明常量或者变量时候,默认应该是有值的。 解决方案 方法一 把属性变为可选类型(一般使用这种) 方法二 直接赋值 方法三 在构造函数中赋值,(需要写在super之前) 父类方法,子类再写一遍 都是在一个类中,方法名相同,参数不同 好处:更灵活,方便记忆,只需要记住方法名即可 所有的方法后带有throws的都应该进行错误处理 使用默认的try时,如果有错误可以通过do—catch进行捕捉,如果没有错误,那就正常执行 do{ let res = try JSONSerialization.jsonObject(with:data,options:[]) print() }catch{ print() } try?如果使用的是可选try,那么如果有错误会返回nil,没有错误就会正常执行 let res = try JSONSerialization.jsonObject(with:data,options:[]) print() try!是强行try,意思是可以放心的用,但是如果是错误的,那么就崩溃了
6、switch
7、字符串的长度、遍历、截取、拼接
——如何获取字符串长度
——如何遍历字符串
——字符串截取
——字符串如何拼接
8、数组定义、拼接、遍历
——数组定义
——如何定义可变和不可变的数组
——如何合并数组
——如何往数组添加元素
——如何移除元素
——如何获取元素
9、函数
——函数类型作为参数
——函数类型作为返回类型
下面的这个例子中定义了两个简单函数,这两个函数的类型都是(Int) -> Int:
如下名为chooseStepFunction(backward:)的函数,它的返回类型是(Int) -> Int类型的函数。
——函数内部定义函数(嵌套函数)
默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。
10、block 闭包
——基本的闭包形式
——尾随闭包
单表达式闭包隐式返回
1、如果有多个参数,最后一个参数为闭包,(这是才称为尾随闭包)那么尾随闭包就会提前把小括号关闭
2、当只有一个参数且为闭包时,那么尾随闭包就会把小括号和参数省略
——逃逸闭包
——闭包的循环引用及解决方法
——原因
——解决方法(三种)
11、面向对象
——重写与重载构造函数
——重写
——重载
12、异常处理
写法为 在所需执行的代码前面写 "try/try?/try!" (其中try与try?比较常用)
方式1 try
方式2 try?
方式3 try!