重学Swift(一)漫谈一些基础

1,641 阅读7分钟

0.Swift语言背景的介绍

  • 历史6年(2014年6月发布),Swift从1.x发展到5.x,经历了多次重大改变,ABI终于稳定
  • ABI(Application Binary Interface):应用二进制接口,应用程序和操作系统之间的底层接口,涉及到:
    • 1.目标的文件格式
    • 2.数据类型的大小,布局,对齐
    • 3.函数的调用约定等等
  • ABI稳定以后,语法不会有太大变动
  • Swift是用C++编写的

1. playground 使用

关于playground的创建和使用这里不赘述了,百谷一堆(😁百度和谷歌一查一堆一堆的),它的优点就是可以试试预览一些结果,比如输入 a+b,他就能反映出a+b的结果,也可以预览一些视图的比如背景色之类的

1.1 常用快捷键

  • cmd + shift + enter 运行整个prayground
  • shift + enter 运行到某行及之前的代码

1.2 视图预览

  • 如果需要预览视图,需要import PlaygroundSupport,然后将要显示的view赋值给以下代码
    • PlaygroundPage.current.liveView = view
    • 如果不显示预览视图,可以试试cmd+option+enter
  • 添加图片资源,cmd+1,展开左边的文件夹目录,将资源拖拽到Resource中,则可以引用图片资源
  • Source文件夹是存放代码文件的
  • 同样也可以创建控制器,不赘述了,详细看demo

1.3 多page介绍

  • Xcode菜单栏 File -> New -> Playground Page 或者 快捷键option+cmd+n
  • 新建的page可以自由修改名字,可以拖动位置,每个page包含单独的SourceResource,在每个page每部的文件夹内的资源是只有当前page可以使用,项目的SourceResource是所有的page都共享的 5.多page

1.4 Markdown语法支持

playground 可以与注释配合生成对Markdown语法的渲染,这里不过多赘述Markdown的语法,百谷一堆。

  • 单行行注释的Marksown://:双反斜杠加冒号,斜杠和冒号之间不能有空格,后面跟单行的Markdow语句
//:# 这是Markdown的一级标题
  • 多行注释注释的Marksown:/*: 这里写Markdown语句 */
/*: 
 # 这是Markdown的一级标题
 ## 这是Markdown的二级标题
 ### 这是Markdown的三级标题
 */
  • 同一个playground下的多个page的跳转 @next@previous

    • //: [下一页](@next)自动跳转到当前page的下一个page,并显示为下一页,如果当前page没有下一页的话,则点击无效
    • //: [上一页](@previous)自动跳转到当前page的上一个page,并显示为上一页,如果当前page没有上一页的话,则点击无效
  • Markdown语法编写完毕之后通过Xcode -> Editor -> Show Rendered Markup

2.简单入门

这一节中我们只是泛泛的简单的演示一些操作,对于有编程基础一看就能懂的东西,不做过多赘述

2.1 我们先创建一个命令行项目,大致观察一下项目结构

1.commandLine 项目图

    // 导包
    import Foundation
    // 打印
    print("Hello, World!")
  • 项目很简单:
    • 仅包含一个main文件,
    • main文件中并没有我们熟悉的main函数,
    • 实现Hello, World!只需要一行代码,更简单甚至可以去掉导包
    • Swift项目的文件的后缀名为.swift,和OC项目不同的是,不再区分声明.h和实现.m
    • 一句代码尾部可以省略分号,多句代码如果在同一一行,必须用分号隔开

2.2 简单了解print

  • 基本打印,在print函数里直接书输入变量名字
  • 字符拼接,只需要在字符串中使用\(变量名)进行包裹即可 TUDO - 基本打印

2.3 简单了解变量和常量

  • 常量
    • let声明不可以重复赋值,重复赋值会报错 2.变量常量报错图
    • 常量不要求在编译期就明确赋值,但是只能赋值1次
    • 未标明类型的常量,或者不能通过自动推断出变量类型的,必须在声明时赋值 6.常量报错图
  • 变量用var声明,可以重复赋值,
  • 变量或者常量不需要声明类型,编译器通过自动推断出类型 3.自动推断

3.Swift数据类型

与OC不同的是,Swift的数据类型大致分类两种,或者三种,按照两种划分

  • 值类型 - enum + struct
  • 引用类型 - class

按照三种划分,可以将enum 和 struct 各自作为一类。enum 这个不足赘述了,后续会详细展开,struct类型的范围是与OC最大的不同,其中Bool Int Float Double Character 以及String Array Dictionary Set都是用struct实现的 7.数据类型

3.1 简单介绍数据类型

整形

  • 整形类型: Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64
  • 在32位系统,Int等价于Int32,64位系统等价于Int64

浮点型:

  • Float 32位,精度6位,

  • Double 64位,精度至少15位

  • 浮点型定义变量时默认为Double,如果是用Float类型时,要显式标注

    // 浮点型
    let double = 15.0 // Double 类型
    let float:Float = 10.0 //Float 类型
    

布尔类型

  • 在OC中 0,1,YES,NO,true,flase都可以作为布尔类型的赋值,但是在Swift中只能是true false,不接受其他值

字符和字符串

  • 字符和字符串都是使用双引号,再不加类型标注的时候默认是字符串,如果是定义字符需要显式的标注

    // 字符 和 字符串
    let string = "字符串"
    let character:Character = "😁"
    

3.2 类型转换

  • Swift在进行数值计算时,不会进行类型自动转换,比如我们以前在OC中一个浮点型 加上 一个整形数据,然后结果会看做浮点型,相当于是自动转换为优先级高的类型,但是在Swift中不允许这样进行计算,要求进行计算的结果变量类型一定是一致的,否则就会报错 8.类型转换

  • Swift类型强转,格式为类型(要转换的值),下面的例子是将Float转换为Double,通过这个例子也能看出,同是浮点类型的数据,也不能直接计算

    // 浮点型
    let double = 15.0 // Double 类型
    let float:Float = 10.0 //Float 类型
    let value = double + Double(float)
    
  • 这里有个例外就是如果字面量直接向加减是不会报错的,因为没有明确的表明类型,最后系统会根据数值进行推断的

    let value = 1 + 0.5
    

4.元组

概念不多介绍了,百谷一堆。介绍几种赋值和定义的方式

// 元组
// 1.基本定义
let tuple = (0,"我是字符串",true)
// 2.根据每个元素名字定义
let (intValue,stringValue,boolValue) = (0,"我是字符串",true)
intValue
stringValue
boolValue
// 3.第二种也可以省略其中不需要取值元素
let (_,stringValue1,boolValue1) = (1,"我是字符串2",true)
// 4.也可以在实现的时候声明元素名字

let tuple2 = (int:2, string: "我是字符串3", bool:true)
tuple2.int
tuple2.string
tuple2.bool

9.元组演示

5.流程控制

5.1 if else

  • 条件判断不需要加小括号,但是大括号不能省略
  • if 后面的条件判断只能是Bool值,和OC中的nil,以及非0为真等判断都不再适用

5.2 while 和 repeat

  • while 循环和OC中没有差别,只是也是可以省略条件判断的小括号

  • repeat 相当于OC中的 do-while,语法如下

    var num = 10
    repeat {
        num -= 1
        print("\(num)")
    } while num > 0
    
    

5.3 for

  • Swift中去掉了 ++ -- 运算符吗,通过 += -= 取代
  • 区间运算符
    • 闭区间运算符:a...b 表示取值>= a 且 <= b
    • 半开区间运算符: a..<b 表示取值>= a 且 < b
    • 单侧区间:让区间炒一个方向无限延伸,当起配合数组使用的时候,会默认在数组的界限内
      • [a...] 表示大于>= a的一些列值
      • [...a] 表示大于<= a的一些列值
      • [..<a] 表示大于< a的一些列值
      • 比如数组array有5个值,那么 array[2...] 表示取值下表为 2 到 4 的3个元素,不能越界,如果越界一样会崩溃
      // 区间运算
      var array = [1,2,3,4,5,6,7]
      for i in array[2...] {
          print(i)
      }
      // 打印结果为 3 4 5 6 7
      
    • contains方法,用以判断当前区间是否包含某个值
    let range = 2...8
    range.contains(2) // true
    range.contains(9) // false
    
    • 区间类型

      • 闭区间是ClosedRange<T>类型

        let r1: ClosedRange<Int> = 1...3
        
      • 半开区间是Range<T>类型

        let r2: Range<Int> = 1..<3
        
      • 单侧区间是PartialRangeThrough<T>类型

        let r3: PartialRangeThrough<Int> = ...3
        
    • 字符串区间值 上面介绍的都是一些Int类型,区间类型也可以用字符串或者字符类型,但是只能表示一系列值,不能用for-in去遍历

    • 带间隔的区间值

  • for 循环去掉了比较经典的三段论(int i=0; i<= N; i++) 取而代之的是类似于for..in的一种拓展,通过区间预算符进行替换
    • 对于通过需要设定一个区间去取值的时候,即实现三段论的方式
      for i in 2...5 {
          print(i)
      }
      // 打印结果为 2 3 4 5
      
      for i in 2..<5 {
          print(i)
      }
      // 打印结果为 2 3 4 
      
    • 也可以直接for in 一个数组
       // 区间运算
       var array = [1,2,3,4,5,6,7]
       for i in array[2...] {
           print(i)
       }
       // 打印结果为 3 4 5 6 7
       ```
    * 数组配合单侧区间元素符,上边已经讲过了
    

5.4switch

基本用法差不多,与C和OCswitch的不同是

  • casedefault后面至少要有一条语句,且不可以用;代替,如果不想做任何操作,可以写一句 break
  • casedefault 下面的语句不能写大括号{},OC中的多行代码的时候需要括起来
  • 默认可以不写break,语句也不会贯穿执行,OC中不写break会贯穿
  • 实现贯穿的两种方式
    • 使用fallthrough替代OC中的break的位置,当前条件就可以贯穿执行
    • 将要贯穿的条件全部写到一个case条件后面

  • case 或者 case + default 必须要覆盖了switch后面所有的值,如果覆盖不到,编译就会报错,比如switch后面的值有5种类型,只case了3种类型,就会报错,不如不需要case 所有情况,就配合 default + break 使用
  • switch 后面的值类型,不再只限定为 Int类型,也支持字符和字符串类型,甚至是无类型的枚举,无类型的枚举在后续文章中会专门进行介绍
  • case 后面值也可以使用刚才提到区间值 和 元组

  • 值绑定:就是在case一个条件的时候,允许部分将一个值的部分进行匹配,剩余部分当做一个变量,进行后续的处理,比如在元组中

    let point = (1,0)
    switch point {
    case (let x,0):
       print("在X轴上值为\(x)")
    case (0,let y):
       print("在y轴上值为\(y)")
    case (let x,let y):
       print("在x轴上值为\(x) - \(y)")
    }
     /-------console-------/X轴上值为1
    
  • where case 还可以写成一个条件表达式,where可以表示上面的值绑定中的变量进行一些比较,或者处理

    //switch where
    let p2 = (1,2)
    switch p2 {
    case let(x,y) where x == y:
        print("x == y")
    case let(x,y) where y > x:
        print("y > x")
    case let(x,y) where y < x:
        print("y < x")
    default:
        break
    }
        /-------console-------/
        y > x
    
  • where - for作为遍历时,作为对元素进行一些条件判断

// for where
let list = [1,2,3,4,5,6,7,8]
for item in list  where item % 2 == 0 {
    print(item)
}