Swift巩固

可选项绑定(Optional Binding)

可以使用可选项绑定来判断可选项是否包含值 p如果包含就自动解包,把值赋给一个临时的常量(let)或者变量(var),并返回true,否则返回false

if let number = Int("123") { 
print("字符串转换整数成功:\(number)") // number是强制解包之后的Int值 // number作用域仅限于这个大括号 } else { print("字符串转换整数失败") }

等价写法

f let first = Int("4") {
    if let second = Int("42") {
        if first < second && second < 100 {
            print("\(first) < \(second) < 100")
} } 
} 
// 4 < 42 < 100 

if let first = Int("4"),
    let second = Int("42"),
    first < second && second < 100 {
    print("\(second) < \(second) < 100")
} 
// 4 < 42 < 100

空合并运算符 ??(Nil-Coalescing Operator)

let a: Int? = 1

let b: Int? = 2

let c = a ?? b // c是Int? , Optional(1)

 

 

let a: Int? = 1

let b: Int = 2

let c = a ?? b // c是Int , 1

 

let a: Int? = nil

let b: Int = 2

let c = a ?? b // c是Int , 2

 

let a: Int? = nil

let b: Int? = 2

let c = a ?? b // c是Int? , Optional(2)

 

let a: Int? = nil

let b: Int = 2// 如果不使用??运算符 let c: Int

if let tmp = a {

    c = tmp

} else {

    c=b

}

 

let a: Int? = nil

let b: Int? = nil

let c = a ?? b // c是Int? , nil

多个 ?? 一起使用

let a: Int? = 1

let b: Int? = 2

let c = a ?? b ?? 3 // c是Int , 1

guard语句

guard语句的条件为false时,就会执行大括号里面的代码

guard语句的条件为true时,就会跳过guard语句

guard语句特别适合用来“提前退出”

当使用guard语句进行可选项绑定时,绑定的常量(let)、变量(var)也能在外层作用域中使用

func login(_ info: [String : String]) {

guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
// if username ....
// if password ....
print("用户名:\(username)", "密码:\(password)", "登陆ing")
} 

guard 条件 else {
// do something.... 

退出当前作用域 

// returnbreakcontinuethrow error }

隐式解包(Implicitly Unwrapped Optional)

在某些情况下,可选项一旦被设定值之后,就会一直拥有值

在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值

可以在类型后面加个感叹号 ! 定义一个隐式解包的可选项

let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
    print(num1 + 6) // 16
}
if let num3 = num1 {
    print(num3)
} 

let num1: Int! = nil
// Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let num2: Int = num1

 

结构体

Swift 标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分

比如BoolIntDouble StringArrayDictionary等常见类型都是结构体

所有的结构体都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法)

类的定义和结构体类似,但编译器并没有为类自动生成可以传入成员值的初始化器

如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无参的初始化器

成员的初始化是在这个初始化器中完成的

class Point {
    var x: Int = 10
    var y: Int = 20
}
let p1 = Point()

class Point {
    var x: Int
    var y: Int
init() { x = 10 
y = 20 } 
}
let p1 = Point()

//上面2段代码是完全等效的 

结构体与类的本质区别

结构体是值类型(枚举也是值类型),类是引用类型(指针类型)

值类型

值类型赋值给var、let或者给函数传参,是直接将所有内容拷贝一份

类似于对文件进行copy、paste操作,产生了全新的文件副本。属于深拷贝(deep copy)

引用类型

引用赋值给var、let或者给函数传参,是将内存地址拷贝一份 p类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件。属于浅拷贝(shallow copy)

Swift中,创建类的实例对象,要向堆空间申请内存

 

枚举、结构体、类都可以定义方法

一般把定义在枚举、结构体、类内部的函数,叫做方法

方法占用对象的内存么

不占用, 

方法、函数都存放在代码段

 

闭包(Closure)

闭包是可以在你的代码中被传递和引用的功能性独立代码块

全局函数是一个有名字但不会捕获任何值的闭包;

内嵌函数是一个有名字且能从其上层函数捕获值的闭包;

 

 

可以把闭包想象成是一个类的实例对象

内存在堆空间

捕获的局部变量\常量就是对象的成员(存储属性)

组成闭包的函数就是类内部定义的方法

 

尾随闭包

如果将一个很长的闭包表达式作为函数的最后一个实参,使用尾随闭包可以增强函数的可读性

尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式

逃逸闭包

当闭包作为一个实际参数传递给一个函数的时候,我们就说这个闭包逃逸了,因为它是在函数返回之后调用的。

当你声明一个接受闭包作为形式参数的函数时,你可以在形式参数前写 @escaping 来明确闭包是允许逃逸的。

 

属性

存储属性(Stored Property)

类似于成员变量这个概念

存储在实例的内存中

结构体、类可以定义存储属性 ü 枚举不可

在创建类 或 结构体的实例时,必须为所有的存储属性设置一个合适的初始值 

可以在初始化器里为存储属性设置一个初始值

可以分配一个默认的属性值作为属性定义的一部分

 

计算属性(Computed Property)

本质就是方法(函数)

不占用实例的内存

枚举、结构体、类都可以定义计算属性

set传入的新值默认叫做newValue,也可以自定义

只读计算属性:只有get,没有set

定义计算属性只能用var,不能用let

let代表常量:值是一成不变的

计算属性的值是可能发生变化的(即使是只读计算属性)

枚举原始值rawValue的本质是:只读计算属性

单例模式

public class FileManager {
    public static let shared = FileManager()
    private init() { }
} 

public class FileManager {
    public static let shared = {
// ....
// ....
r
eturn FileManager() 
}() 
    private init() { }
}

初始化器

类、结构体、枚举都可以定义初始化器

类有2种初始化器:指定初始化器(designated initializer)、便捷初始化器(convenience initializer)

每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器

默认初始化器总是类的指定初始化器

类偏向于少量指定初始化器,一个类通常只有一个指定初始化器

 

初始化器的相互调用规则

指定初始化器必须从它的直系父类调用指定初始化器

便捷初始化器必须从相同的类里调用另一个初始化器

便捷初始化器最终必须调用一个指定初始化器

// 指定初始化器
 init(parameters) { 
statements } 
// 便捷初始化器

convenience init(parameters) { 
statements }

重写

当重写父类的指定初始化器时,必须加上override(即使子类的实现是便捷初始化器)

如果子类写了一个匹配父类便捷初始化器的初始化器,不用加上override

因为父类的便捷初始化器永远不会通过子类直接调用,因此,严格来说,子类无法重写父类的便捷初始化器

1、如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器

如果子类提供了父类所有指定初始化器的实现(要么通过方式1继承,要么重写)

required

用required修饰指定初始化器,表明其所有子类都必须实现该初始化器(通过继承或者重写实现) 

如果子类重写了required初始化器,也必须加上required,不用加override

属性观察器

父类的属性在它自己的初始化器中赋值不会触发属性观察器,但在子类的初始化器中赋值会触发属性观察器

 

反初始化器(deinit)

einit叫做反初始化器,类似于C++的析构函数、OC中的dealloc方法

当类的实例对象被释放内存时,就会调用实例对象的deinit方法 

class Person {
    deinit {
print("Person对象销毁了") } 
} 

deinit不接受任何参数,不能写小括号,不能自行调用

父类的deinit能被子类继承

子类的deinit实现执行完毕后会调用父类的deinit

 

协议(Protocol)

协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)

协议中定义属性时必须用var关键字

实现协议时的属性权限要不小于协议中定义的属性权限

 

协议的继承

一个协议可以继承其他协议

protocol Runnable {
    func run()
} 
protocol Livable : Runnable {
    func breath()
} 
class Person : Livable {
    func breath() {}
    func run() {}
}

CaseIterable

让枚举遵守CaseIterable协议,可以实现遍历枚举值

num Season : CaseIterable {
    case spring, summer, autumn, winter
}
let seasons = Season.allCases print(seasons.count) // 4 for season in seasons { 
    print(season)
} // spring summer autumn winter

isas?as!as

is用来判断是否为某种类型,as用来做强制类型转换

 

自定义错误

Swift中可以通过Error协议自定义运行时的错误信息

enum SomeError : Error {

case illegalArg(String) 
case outOfBounds(Int, Int) 
case outOfMemory 
} 

函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明

unc divide(_ num1: Int, _ num2: Int) throws -> Int {
 if num2 == 0 { 
throw SomeError.illegalArg("0不能作为除数")
 } 
    return num1 / num2
}

需要使用try调用可能会抛出Error的函数

var result = try divide(20, 10)

do-catch

可以使用do-catch捕捉Error

func test() {
    print("1")
    do {
        print("2")
        print(try divide(20, 0))
print("3") 
        }  catch let SomeError.illegalArg(msg) {
 
print("参数异常:", msg) 

        }  catch let SomeError.outOfBounds(size, index) { 

print("下标越界:", "size=\(size)", "index=\(index)") 

        }  catch SomeError.outOfMemory { 

print("内存溢出") } catch {
 
print("其他错误") } 
print("4") } 

try?try!

可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error

assert(断言)

很多编程语言都有断言机制:不符合指定条件就抛出运行时错误,常用于调试(Debug)阶段的条件判断 n 默认情况下,Swift的断言只会在Debug模式下生效,Release模式下会忽略

func divide(_ v1: Int, _ v2: Int) -> Int { 
assert(v2 != 0, "除数不能为0")

return v1 / v2 
}
print(divide(20, 0))

泛型(Generics)

泛型可以将类型参数化,提高代码复用率,减少代码量

泛型函数赋值给变量

func swapValues<T>(_ a: inout T, _ b: inout T) {
 (a, b) = (b, a) 
}

 

继承(Inheritance)

值类型(枚举、结构体)不支持继承,只有类支持继承

没有父类的类,称为:基类

Swift并没有像OC、Java那样的规定:任何类最终都要继承自某个基类

子类可以重写父类的下标、方法、属性,重写必须加上override关键字

重写属性

子类可以将父类的属性(存储、计算)重写为计算属性

子类不可以将父类属性重写为存储属性

只能重写var属性,不能重写let属性

重写时,属性名、类型要一致 

子类重写后的属性权限 不能小于 父类属性的权限

如果父类属性是只读的,那么子类重写后的属性可以是只读的、也可以是可读写的

如果父类属性是可读写的,那么子类重写后的属性也必须是可读写的

重写类型属性

class修饰的计算类型属性,可以被子类重写

static修饰的类型属性(存储、计算),不可以被子类重写

可以在子类中为父类属性(除了只读计算属性、let属性)增加属性观察器

final

被final修饰的方法、下标、属性,禁止被重写

被final修饰的类,禁止被继承

访问控制(Access Control)

在访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列, 实体指被访问级别修饰的内容)

open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上) 

public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写

internal:只允许在定义实体的模块中访问,不允许在其他模块中访问

fileprivate:只允许在定义实体的源文件中访问 

private:只允许在定义实体的封闭声明中访问 

绝大部分实体默认都是internal 级别

 

Swift调用OC

新建1个桥接头文件,文件名格式默认为:{targetName}-Bridging-Header.h

{targetName}-Bridging-Header.h 文件中#import OC需要暴露给Swift的内容

OC调用Swift

Xcode已经默认生成一个用于OC调用Swift的头文件,文件名格式是: {targetName}-Swift.h

Swift暴露给OC的类最终继承自NSObject

使用@objc修饰需要暴露给OC的成员

使用@objcMembers修饰类

Xcode会根据Swift代码生成对应的OC声明,写入{targetName}-Swift.h 文件

String

NSString

String

NSMutableString

Array

NSArray

Array

NSMutableArray

Dictionary

NSDictionary

Dictionary

NSMutableDictionary

Set

NSSet

Set

NSMutableSet

KVC\KVO

Swift 支持 KVC \ KVO 的条件

属性所在的类、监听器最终继承自 NSObject

@objc dynamic 修饰对应的属性

class Person: NSObject {
    @objc dynamic var age: Int = 0
    var observer: Observer = Observer()
    override init() {
    super.init() 
    self.addObserver(observer, 
    forKeyPath: "age", options: .new, context: nil) 
    }

    deinit { 
    self.removeObserver(observer, forKeyPath: "age") 
    } 
} 

var p = Person()

// observeValue Optional(20) 
p.age = 20

// observeValue Optional(25) 
p.setValue(25, forKey: "age") 

class Observer: NSObject {

override func observeValue(forKeyPath keyPath: String?, 
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?) {
print("observeValue", change?[.newKey] as Any) } 
}

 

原文地址:https://www.cnblogs.com/ljcgood66/p/14173663.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。