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 + 协议名)