swift5.1版本学习

swift各种demo社区:https://www.hangge.com




一、

1、字符串的用法

let  apples =3

let   oranges =5

let   appleSummary ="I have\(apples)apples."

let   fruitSummary ="I have\(apples + oranges)pieces of fruit."

可以直接 用引号 进行 把 数据类型进行转换 字符串!"\(number)"

Double精度问题

使用函数 :String(format: <#T##String#>, <#T##arguments: CVarArg...##CVarArg#>)

var f = 123.32342342

var s:String = "\(f)" //123.32342342   小数全保留

var s = String(format: "%.2f", f) //123.32  小叔精确两位

var s = String(format: "%06x", i) //000123.32342342  前面不足补零


二、

2、数据类型

Int  一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型 Int,长度与当前平台的原生字长相同:

数值型类型转换:    【swift不同类型的数据类型不能 运算!!!!!

1>整数转换  let one: UInt8 = 1    UInt16(one)

2>整数和浮点数转换 let three = 3  Double(three)

3、类型别名 typealias AudioSample =  UInt16   // typealias 别名 =  原名

4、元祖的访问:let http404Error = (404, "Not Found")

  1>自定义变量  解析元祖 let (statusCode, statusMessage) = http404Error    ——> print("The status code is \(statusCode)")

2>通过  【下标】  来访问元组中的单个元素,下标从零开始:print("The status code is \(http404Error.0)")

3>通过  【名字】  来获取这些元素的值(类似字典写法):let http200Status = (statusCode: 200, description: "OK")

print("The status code is \(http200Status.statusCode)")

5、可选类型:Swift 中,nil 不是指针——它是一个确定的值,用来表示 值缺失任何类型  的可选状态都可以被  设置为 nil

6、可选类型的解析值 ——> 可选绑定

if let constantName = someOptional { statements}   // 如果 someOptional有值得话,则会constantName会进行赋值

这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。

if someOptional != nil { }  这样就可以了!!

7、断言和先决条件:断言和先决条件的不同点是,他们什么时候进行状态检测:【断言仅在调试环境运行】,而 【先决条件则在调试环境和生产环境中运行】。在生产环境中,断言的条件将不会进行评估。这个意味着你可以使用很多断言在你的开发阶段,但是这些断言在生产环境中不会产生任何影响。

如果断言或者先决条件中的布尔条件评估的结果为 true(真),则代码像往常一样继续执行。【如果布尔条件评估结果为 false(假),程序的当前状态是无效的,则代码执行结束,应用程序中止。】

1>断言 (条件为假,则会触发 断言)

 let age = -3 

assert(age >= 0) // 省略 断言信息

assert(age >= 0, "A person's age cannot be less than zero")// 因为 age < 0,所以断言会触发 ——> 终止应用。

2>先决条件

precondition(index > 0, "Index must be greater than zero.")

三、switch 

1、元组:元组中的元素可以是值,也可以是区间。另外,使用下划线(_)来匹配所有可能的值。

let somePoint = (1, 1) 

switch somePoint { 

case (0, 0): 

               print("\(somePoint) is at the origin") 

case (_, 0): 

                print("\(somePoint) is on the x-axis") 

default:

              print("\(somePoint) is outside of the box")}

2、值绑定(Value Bindings)

let anotherPoint = (2, 0) 

switch anotherPoint { 

case (let x, 0): 

      print("on the x-axis with an x value of \(x)") 

case (0, let y): 

      print("on the y-axis with a y value of \(y)") 

case let (x, y) where x == y

       print("(\(x), \(y)) is on the line x == y")}

3、Where   case 分支的模式可以使用 where 语句来判断额外的条件

4、复合型 Cases

let someCharacter: Character = "e"

 switch someCharacter { 

case "a", "e", "i", "o", "u": 

            print("\(someCharacter) is a vowel") 

case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": 

            print("\(someCharacter) is a consonant") 

default: print("\(someCharacter) is not a vowel or a consonant")}

四、检测API可用性

if #available(平台名称 版本号, ..., *) { 

             APIs 可用,语句将执行} else { 

             APIs 不可用,语句将不执行}

if #available(iOS 10, macOS 10.12, *) {

               // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API} else { 

               // 使用先前版本的 iOS 和 macOS 的 API}

五、函数闭包 ——> 闭包 只是代码!!只有在 触发闭包时,才会执行代码!!

1>逃逸闭包 @escaping:当一个  【闭包作为 参数】 传到一个函数中,但是这个 【闭包在函数  返回之后 才被执行】,我们称该闭包从函数中逃逸。定义接受闭包作为参数的函数时,你可以在参数名之前标注 【@escaping】

2>自动闭包 @autoclosure (能不用就不用):(前提,闭包里就【一行表达式的闭包!!!!】 适合 用自动闭包!!)闭包里的执行代码 (直接—>去掉大括号) 作为参数 为显式的闭包。——> 这个代码不会执行,只是一个参数,在函数里闭包被调用时才会执行!【有延迟执行的效果!!!!作为参数这行代码只是代码而不会执行!!】  【只有@autoclosure 修饰的闭包类型参数 才可以使用 】

过度使用 autoclosures 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。

注意:

1>Swift 有如下要求:只要在闭包内使用 self 的成员,就要用 self.someProperty 或者 self.someMethod()(而不只是 someProperty 或 someMethod())。这提醒你可能会一不小心就捕获了 self。

2>如果被捕获的引用  绝对不会变为 nil,应该用无主引用,而不是弱引用。【弱引用总是可选类型】,并且当引用的实例被销毁后,弱引用的值会自动置为 nil。这使我们可以在闭包体内检查它们是否存在。

六、枚举

1、枚举访问元素 。使用时,【变量的类型不明确,则使用 Enum.item      如果变量明确 直接使用   .item】

2、枚举的遍历:令枚举遵循 CaseIterable 协议。Swift 会生成一个 allCases 属性,用于表示一个包含枚举所有成员的集合。

enum Beverage: CaseIterable {case coffee, tea, juice}

for beverage in Beverage.allCases {print(beverage)}

3、关联值(代存储):可以定义 Swift 枚举来  【存储任意类型的关联值】前提 枚举item 要设置 类型!——> 遍历的时候,可以取 这关联值!  (设置类型 ——> 外部 赋值存储 ——> 遍历 定义变量 取值 )

【关联值 三法 ——> 设、赋、变!】

  原始值 :默认值(称为原始值)预填充,这些  原始值的类型必须相同!——> 设置枚举的类型!!! 才可以有原始值

4、与 C 和 Objective-C 不同,Swift 的枚举成员在被创建时   ——> 不会被赋予一个默认的整型值!!。在上面的 CompassPoint 例子中,north,south,east 和 west 不会被隐式地赋值为 0,1,2 和 3。相反,【这些枚举成员本身就是完备的值】,这些值的类型是已经明确定义好的 CompassPoint 类型。

enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune}

directionToHead = .south 

switch directionToHead { 

case .north: print("Lots of planets have a north")

 case .south:  print("Watch out for penguins") 

case .east: print("Where the sun rises") 

case .west: print("Where the skies are blue")}

5、if case 语法、for case 语法 、guard case语法  https://www.jianshu.com/p/f935c4db7333

七、结构体和类

1、所有结构体  都有一个 自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。(默认把所有属性都带上去了!!!

类:默认是有一个 init () {}  构造器,但是 构造器里一个参数都没有!!需要我们自己生产!构造器

2、结构体和枚举  是值类型  ——> 值类型是这样一种类型,当它被赋值给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。(但是 swift中集合、数组、字典 被优化了,先共用 一个内存空间,如有变动则会再拷贝一份!)

3、属性:类属性,【必须赋值】!必须static和class关键字进行修饰!!只第一次访问时才初始化,且只初始化一次!

4、全局变量和局部变量:【全局变量】是在函数、方法、闭包或任何类型之外定义的变量。【局部变量】是在函数、方法或闭包  内部定义的变量。注意:【全局的常量或变量都是延迟计算的】!!!!,跟 延时加载存储属性 相似,不同的地方在于,全局的常量或变量不需要标记 lazy 修饰符。局部范围的常量和变量从不延迟计算。——>

【全局属性定义的时候 内部 set和get不进行运行,只有在用的时候 才 触发 set和get方法!】

【因为 变量 、常量  本质 是 set/get 方法 ——> 方法只有在调用的时候才触发!】

5、下标:定义下标使用 subscript 关键字,与定义实例方法类似,都是指定一个或多个输入参数和一个返回类型。与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,类似计算型属性:

6、Any 可以表示  任何类型,包括函数类型。

    AnyObject 可以表示  任何类类型的—> 实例。      

八、扩展 :必须自己实现

1>添加  计算型实例属性和计算型类属性  【只能是 变量 var 而且 只能有 get方法!!】——> 只有get方法!

并且 原有类已有的   属性   和 方法    不可以 在 扩展中 再 添加!!

2>扩展 可以给一个类添加   【新的便利构造器!】,但是它们  【不能 添加 指定构造器或者析构器!!!】。【指定构造器和析构器必须    始终  由类  的原始实现提供】。

扩展 && 协议 :

属性:扩展只可以 get方法  、协议 set/get 都可以

方法:类方法、对象方法 都可以

构造器:扩展 只可以 添加 遍历构造器  、协议 可以添加 指定构造器 和 遍历构造器

九、协议 : 不用实现

1>类、结构体或枚举都可以遵循协议

2>协议通常!用 var 关键字来声明变量属性 ,在类型声明后加上 { set get } 来表示属性是可读可写的,可读属性则用 { get } 来表示:

3>【协议中  可以添加 指定构造器! 和 便利构造器!】在 实现类 中 ——> 必须添加 关键字:required:必须实现

4> 协议 可以 当作 一种 类型  使用:尽管协议本身并未实现任何功能,但是协议可以被当做一个【功能完备的类型】来使用。协议作为类型使用,有时被称作「存在类型」,这个名词来自「存在着一个类型 T,该类型遵循协议 T」。

协议作为类型 ——> 理解为 一个 特殊的泛型!! 只要是遵守这个类型的协议,都可以把  实例 赋值给这个参数!但是,这个 协议类型的参数 在使用过程中, 必须 使用 协议中的属性和方法  !!!!

5、在扩展里添加协议遵循——> 让原类 间接遵守这个协议

6、协议的继承 ——> 给原有的协议 添加 新的协议!

7、协议扩展:协议也可以进行扩展,【协议的  扩展默认  可以  直接   进行实现该方法】!!!

8、可选的协议要求:  

1>【optional】 关键字作为前缀来定义可选要求  

2> 可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上 @objc 属性。【标记 @objc 特性的协议只能被继承自 Objective-C 类的类或者 @objc 类遵循】,其他类以及结构体和枚举均不能遵循这种协议。

严格来讲,【@objc协议】 协议中的  【 方法和属  性都是可选的】,因此遵循协议的类 可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。

9、协议合成:协议组合使用 SomeProtocol & AnotherProtocol 的形式,要求 【参数】 必须同时遵守多个协议!

十、循环引用:

1> 注意

如果被捕获的引用绝对不会变为 nil,应该用无主引用 unowned 。

弱引用:可能为nil空值  用 weak

十一、GCD用法

DispatchQueue ——> DispatchObject ——> OS_object ——> NSObject  //swift中的  DispatchQueue 集成 NSObject 是一个 类 !底层 runtime 执行。

queue.suspend() //暂停

queue.resume()  // 恢复

1>全局队列 :

DispatchQueue.global(qos: .default).async {      }//异步

DispatchQueue.global(qos: .default).sync {      }//同步

2>自定义队列

串行:let queue:DispatchQueue = DispatchQueue(label: "processQueueName")  // 默认串行 队列

并发: let queue:DispatchQueue = DispatchQueue(label: "processQueueName", attributes: .concurrent)

除了直接使用 DispatchQueue.global().async 这种封装好的代码外,还可以通过DispatchWorkItem自定义队列的优先级,特性:

let queue = DispatchQueue(label: "swift_queue")

 let dispatchworkItem = DispatchWorkItem(qos: .userInitiated, flags: .inheritQoS) { } //可以开辟任务!

queue.async(execute: dispatchworkItem)

3>主队列:DispatchQueue.main.async {       }

4>线程组

DispatchQueue.global().async(group: DispatchGroup.init(), execute: DispatchWorkItem.init {      //线程任务     })

5>延迟定时器

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {    Print("延迟执行的函数")     }

6、swift中的单利:就是常量!

// 用let 创建常量 

static let shareSingleOne = SingleInstanceOne()


十二、不透明类型 (some + 协议名)

1
2

推荐阅读更多精彩内容