0%

引用

html引用css:
css导入css: @import ‘init.css’ (模块化)

@规则

@charset 设置样式表的编码
@import 导入其他样式文件
@media 媒体查询
@font-face 自定义字体

居中解决方案

水平居中

要求父子级都是块元素
.insideDiv {
margin: 0 auto; // 上下0, 左右自适应
}

垂直居中

等待更新。。。

盒子模型

外边距 margin
边框 border
内边距 padding
宽高 width+height (宽高指是内容的宽高)
盒子的总大小=width/height + padding +border + margin (注意两侧会是2倍)
盒子的可视大小=width/height + padding +border (注意两侧会是2倍)

定位 position

static: 默认, 对象遵循常规流
absolute: 相对于离自身最近的定位祖先元素定位; 若没有, 相对于文档定位
relative: 保留原本位置定位, 用偏移属性后相对原位置定位
fixed: 相对于浏览器定位
sticky: 在屏幕中时和relative一致, 在屏幕外时和fixed一致 (吸附效果)

float

作用: 块级元素合并一行
float: left/right
设置此属性后, 浮动元素产生了浮动流
效果: 不影响块级元素位置(可能重叠); 但会影响bfc元素、文本元素(inline)和文本的位置
块级元素(如div)无法包住浮动元素

  • 方案1: 清除浮动元素后面的浮动流
    具体操作: 在::after伪元素设置clear: both属性(在此之前display: block, content: “”, 因为clear只能应用于块级元素), 用以清除浮动流
  • 方案2: 修改父级属性,使之可以看到浮动元素
    具体操作: 父级设置成float、absolute后等
    副作用: position: absolute或float: left/right后, 元素会被内部转换成inline-block;

文本

溢出

单行文本, 溢出省略:
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
多行文本, 溢出省略:
PC端老版本的浏览器, 前端不好计算, 后端计算
多行文本, 溢出截断(多行可能更常用的方法):
overflow: hidden;
(text-overflow 默认 clip)

font-size

数字 / 百分比 / em / px 都可以表示font-size, 除px外都是父级font-size乘以倍数
但直接使用数字, 子级可以继承父级的line-height比例, 而不是继承相乘后的px
结论: 推荐line-height使用数字
写法: font: 12px/1.5 字体

background

background-image: url();
background-size: 1px;
background-repeat: no-repeat;
background-position: 1px 1px /center center;
整合background

  • background-image
  • background-position
  • background-size
  • background-repeat
  • background-attachment
  • background-origin
  • background-clip
  • background-color

文字代替图片

当网络不佳或浏览器问题加载不出图片时, 用文字代替图片的两种方案
方案一: 让padding加载background-image, 图片溢出容器, 然后隐藏(淘宝方案)
height: 0px;
padding-top: 容器高度px;
overflow: hidden;
方案二: 文字缩紧出容器并隐藏
text-indent: 容器宽度px;
white-space: nowrap;
overflow: hidden;

注意点

行级元素只能套行级元素
块级元素可以套行级元素
⚠️例外: p 不能套 div

CSS经典bug

margin塌陷

bug: 父级有margin-top, 而子级也有, 这时候子级不会根据父级,在垂直方向进行偏移
解决方案: 触发block format context
具体操作: 父级设置如下其中之一属性, position:absolute; display: inline-block; float: left/right; overflow: hidden;

margin合并

bug: 上下两个div分别设置了margin-bottom和margin-top, 两者会合并, 而不是累加
解决方案: 可以用触发bfg解决, 但实际开发只用一边的margin来解决

CSS简单选择器

id

示例:

<div id="username"></div> 
# username { 
background: red; 
} 

class

示例:

<div class="coupon selectedCoupon"></div> 
.coupon { 
width:100%; 
} 
.selectedCoupon { 
background: red; 
} 

标签选择器

示例:

div { 
width:100%; 
} 

通配符

* { 
background: #FFF; 
} 

特定选择器

[id] { 
background: white; 
} 
[id="username"] { 
background: red; 
} 
[class] { 
width: 100%; 
} 

复杂选择器

父子选择器/派生选择器

.wrapper #box span { 
background: red; 
} 

直接子元素选择器

wrapper class下的直接一级子元素, 不包含更下级的子元素

.wrapper > child { 
background: red; 
} 

并列选择器

多个条件并列的选择器
针对div且是class为box的元素

div.box { 
background: red; 
} 

分组/群组选择器

多个选择器使用同一个css样式

.demo, .demo2 { 
background: red; 
} 

伪类选择器

.myDiv:hover { 
background: red; 
} 

伪元素选择器

伪元素默认是行级元素

span::before { 
background: red; 
} 

权重

一个样式是否作用于元素依赖于这个样式的权重和如下所示样式来源的顺序,下面这个列表中越靠前的权重越小:

  • 用户代理声明(译注:如浏览器默认样式)
  • 用户声明(译注:如用户浏览器选项设置或通过开发人员调试工具修改)
  • 开发者声明(译注:如页面中引用的CSS)
  • 带有!important的开发者声明
  • 带有!important的用户声明
    警告⚠️: 永不使用important, 否则最终会难以维护

权重比较

元素 权重
!important infinity
内联样式=行间样式(style=””) 1000
id(#myid) 100
class/属性/伪类(.class/[type]/:hover, :link, :target) 10
标签/伪元素(div/::after, ::before, ::fist-inline, ::selection) 1
通配符(*) 0

寻找同一行的最高级的权重,并求和,进行对比,若一致则对比低一级的权重,递归往下直到没有选择器

基础属性

根据CSS参考手册查询

相关文档和视频

2021权威「HTML+CSS」零基础入门精英课【渡一教育】
css的优先级和权重
CSS参考手册

HTML

根标签, html文件中是唯一的 结构化标签, 设置浏览器特性 结构化标签, 客户端展示

html

告诉搜索引擎使用的语言, SEO搜索引擎优化时有用

设置字符集

设置关键字 设置标题

body

常用标签

标签名 标签作用
h1 - h6 标题标签(header), h1 - h6 逐渐减小
strong 加粗标签, 但一般不使用(css与html分离)
em 斜体标签, 但一般不使用(css与html分离)
del 删除标签(delete), 一般用于价格划线, 但一般不使用, 而是text-decoration: line-through 代替
span 容器标签(跨度), 一行展示, 捆绑操作
address 地址标签, 等价于p + em标签
div 容器标签(division), 独行展示, 捆绑操作
p 段落标签(paragraph), 让p标签内的文字成段展示

列表标签

有序标签
<ol>
小写字母<ol type="a"> ;
大写字母 <ol type="A"> ;
罗马数字小写 <ol type="i"> ;
罗马数字大写 <ol type="I">;
排列顺序 <ol reversed="reversed">
初始索引: <ol start="2">

无序标签
<ul>
默认: 实心圆 <ul type="discircle">;
空心圆 <ul type="circle">;
方块 <ul type="square">
列表标签 <li>

图片标签

<img src="" alt="图片占位符, 图片炸了之后显示" title="图片显示符">

超链接标签

anchor 锚点 最开始的作用是前往页面的某个位置
作用1、超链接
<a href="" target="\_blank"> target=”_blank” 新标签页打开页面
作用2、打电话
<a href="tel:12345678912">
作用3、发邮件
<a href="mailto:a@b.c">
作用4、协议限定符
<a href="javascript:alert('emmm')">click me </a>

表单标签

1
2
3
4
5
6
<form method="get" action="https://www.baidu.com"> 
<input type="text" name="username">
<input type="password">
<input type="radio" name="selection" value="1">
<input type="checkbox">
</form>

单标签

换行 <br>
水平线 <hr>

html编码

空格 &nbsp; (non-breaking space 不间断空格)
小于符 < (less than)
大于符 > (greater than)

行级元素和块级元素

实际此为css特性, 可以用css修改改变
display: inline / block / inline-block

行级元素/内联元素

特点: 内容决定元素所占位置, 不可以通过css改变宽高
常见元素: span, strong, del, em, h1

块级元素

特点: 可以独占一行, 可以通过css改变宽高
常见元素: div, p, li, ul, ol, form, address

行级块元素

特点: 内容决定元素所占位置, 可以通过css改宽高
常见元素: img
补充: 凡是有inline属性的元素, 都有文字特性, 所以会被分割, 即使是图片也如此

相关文档和视频

2021权威「HTML+CSS」零基础入门精英课【渡一教育】

题目描述

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

给出两个整数 x 和 y,计算它们之间的汉明距离。

示例:

输入: x = 1, y = 4

输出: 2

解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑

上面的箭头指出了对应二进制位不同的位置。

解题思路

求x和y的异或, 然后统计二进制数中1的个数

1
2
3
4
5
class Solution {
class func hammingDistance(_ x: Int, _ y: Int) -> Int {
return (x ^ y).nonzeroBitCount
}
}

题目描述

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。

解题思路

同时遍历二叉树即可

个人解题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class TreeNode {
var val: Int
var left: TreeNode?
var right: TreeNode?
init(_ val: Int) {
self.val = val
self.left = nil
self.right = nil
}
}

class Solution {

func mergeTrees(_ t1: TreeNode?, _ t2: TreeNode?) -> TreeNode? {

var node: TreeNode?

if let tree1 = t1, let tree2 = t2 {
node = TreeNode(tree1.val + tree2.val)
} else if t1 != nil && t2 == nil {
node = TreeNode(t1!.val)
} else if t2 != nil && t1 == nil {
node = TreeNode(t2!.val)
} else {
return nil
}

node?.left = mergeTrees(t1?.left, t2?.left)
node?.right = mergeTrees(t1?.right, t2?.right)

return node

}

}

优化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {

func mergeTrees(_ t1: TreeNode?, _ t2: TreeNode?) -> TreeNode? {

guard let tree1 = t1 else { return t2 }
guard let tree2 = t2 else { return t1 }

let node = TreeNode(tree1.val + tree2.val)
node.left = mergeTrees(tree1.left, tree2.left)
node.right = mergeTrees(tree1.right, tree2.right)
return node

}

}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-binary-trees

前言

iOS 13 新增了(Sign in with Apple)苹果登陆的方式,而苹果要求除特殊情况,只要加入了第三方登录,也必须有苹果登陆这一选项

简介

Sign in with Apple会在用户首次使用时进行授权,开发者可以获得用户的姓名(随意修改)和邮箱(明文/密文)

若邮箱为密文邮箱,需要在通过苹果提供的邮箱中继服务发送

Sign in with Apple的平台,分为App端、Web端,以及服务器端对信息的验证

开发前的准备

1、在开发证书中,选择Sign in with Apple权限
2、若需要服务端验证和Web端授权登陆,还需要注册Services ID,配置网站域名和回调地址,以及创建密钥

App端授权

Web端授权

服务端验证

参考文章:

Configuring Your Webpage for Sign in with Apple
Sign in with Apple 登录详解
iOS 13-Sign In with Apple
Sign in with Apple - IOS应用服务端的处理
Sign in with Apple Tutorial

GCD简介

GCD全称Grand Central Dispatch,中央调度中心
它主要用于优化多核处理器和其他对称处理系统
它在一个线程池模式的基础上执行并发的任务

GCD的两大核心概念:任务、队列

任务

任务,即指执行操作,也就是执行的代码,它一般放在block中
在GCD中,执行任务的两大方式:同步执行、异步执行
两者的区别:任务是否立即执行、是否具备开辟新线程的能力

同步执行

同步添加任务到指定队列后,任务不会立即执行,需要等待队列前面的任务执行完成后,再执行此任务
只能在当前队列执行任务,不具备开辟新线程的能力

异步执行

异步添加任务到指定队列后,任务会立即执行
可能会开辟新的线程执行任务,具备开启新线程的能力

队列

队列,即指执行任务的等待队列,它是一种特殊的线性表,遵守FIFO(First in First Out)原则,即队尾插入新任务,队头读取任务
在GCD中,队列的两种类型:并行队列、串行队列

串行队列

每次只执行一个任务,当它执行完毕后,再执行下一个任务(只开启一个线程)

并行队列

可以让多个任务并发(同时)执行(可以开启多个线程)

注意
并发队列的并发功能只有在异步(dispatch_async)方法下才有效。

GCD的使用

GCD的创建分两步:
1、创建一个队列(串行/并行队列)
2、将任务追加到队列中,然后系统根据任务类型执行任务(同步/异步任务)

队列的创建

调用以下方法来创建队列:
dispatch_queue_create(const char * _Nullable label, dispatch_queue_attr_t _Nullable attr)
第一个参数:队列的唯一标识符,一般用App ID这样的逆序全程域名
第二个参数:队列的类型,DISPATCH_QUEUE_SERIAL是串行队列,DISPATCH_QUEUE_CONCURRENT是并行队列

1
2
3
4
5
// 创建串行队列
dispatch_queue_t queueSerial = dispatch_queue_create(@"io.github.gaoxiangzhang-abner", DISPATCH_QUEUE_SERIAL);

// 创建并行队列
dispatch_queue_t queueConcurrent = dispatch_queue_create(@"io.github.gaoxiangzhang-abner", DISPATCH_QUEUE_CONCURRENT);

默认提供的队列

对于串行队列,GCD默认提供『主队列(Main Dispatch Queue)』

1
2
// 主队列
dispatch_queue_t queueMain = dispatch_get_main_queue();

注意:主队列其实并不特殊,主队列的实质上就是一个普通的串行队列
只是默认情况下,当前代码是放在主队列中的,然后主队列中的代码都会放到主线程中去执行

对于并行队列,GCD默认提供『全局并发队列(Global Dispatch Queue)』
dispatch_get_global_queue: 获取全局列队,
其中第一个参数为优先级,可选的优先级有以下几个,从上到下优先级依次降低:
QOS_CLASS_USER_INTERACTIVE
QOS_CLASS_USER_INITIATED
QOS_CLASS_DEFAULT
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND
该函数的第二个参数为系统保留,每次都传入 0 即可。通常我们第一个参数也传入 0 来获取默认的全局列队。

1
2
3
// 全局并发队列
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_queue_t queueGlobal2 = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);

任务的创建

1
2
3
4
5
6
7
8
9
// 同步执行任务的方法创建
dispatch_sync(queue, ^{
// 执行的代码
});

// 异步执行任务的方法创建
dispatch_async(queue, ^{
// 执行的代码
});

任务和队列的组合

GCD提供了2种队列(串行队列/并行队列),2种任务执行方式(同步执行/异步执行),以及主队列和全局并发队列,其中全局并发队列可以作为普通并发队列使用,而主队列需要研究
因此有6种组合方式:
串行队列 + 同步执行
串行队列 + 异步执行
并行队列 + 同步执行
并行队列 + 异步执行
主队列 + 同步执行
主队列 + 异步执行

我们先来考虑最基本的使用,也就是当前线程为 『主线程』 的环境下,『不同队列』+『不同任务』 简单组合使用的不同区别。暂时不考虑 『队列中嵌套队列』 的这种复杂情况。

『主线程』中,『不同队列』+『不同任务』简单组合的区别:

区别 并发队列 串行队列 主队列
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁卡住不执行
异步(async) 有开启新线程,并发执行任务 有开启新线程(1条),串行执行任务 没有开启新线程,串行执行任务
注意:从上边可看出: 『主线程』 中调用 『主队列』+『同步执行』 会导致死锁问题。

这是因为在『主线程』的『主队列中追加的同步任务』和『主线程本身的任务』两者之间相互等待,阻塞了『主队列』,最终造成了主队列所在的线程(主线程)死锁问题。
而如果我们在『其他线程』调用『主队列』+『同步执行』,则不会阻塞『主队列』,自然也不会造成死锁问题。最终的结果是:不会开启新线程,串行执行任务。

实际在使用『串行队列』的时候,也可能出现阻塞『串行队列』所在线程的情况发生,从而造成死锁问题。这种情况多见于同一个串行队列的嵌套使用。

比如下面代码这样:在『异步执行』+『串行队列』的任务中,又嵌套了『当前的串行队列』,然后进行『同步执行』

1
2
3
4
5
6
7
8
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{ // 异步执行 + 串行队列
dispatch_sync(queue, ^{ // 同步执行 + 当前串行队列
// 追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
});
});

执行上面的代码会导致『串行队列中追加的任务』和『串行队列中原有的任务』
两者之间相互等待,阻塞了『串行队列』,最终造成了串行队列所在的线程(子线程)死锁问题。
主队列造成死锁也是基于这个原因,所以,这也进一步说明了主队列其实并不特殊

区别 『异步执行+并发队列』嵌套『同一个并发队列』 『同步执行+并发队列』嵌套『同一个并发队列』 『异步执行+串行队列』嵌套『同一个串行队列』 『同步执行+串行队列』嵌套『同一个串行队列』
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁卡住不执行 死锁卡住不执行
异步(async) 有开启新线程,并发执行任务 有开启新线程,并发执行任务 有开启新线程(1条),串行执行任务 有开启新线程(1 条),串行执行任务

类比

通过一个类比来理解 队列、任务 以及 线程 之间的关系

假设现在有5个人要穿过一道门禁,这道门禁总共有10个入口
管理员可以决定同一时间打开几个入口,可以决定同一时间让一个人单独通过还是多个人一起通过
不过默认情况下,管理员只开启一个入口,且一个通道一次只能通过一个人

这个故事里,人好比是『任务』,管理员好比是『系统』,入口则代表『线程』

5 个人表示有 5 个任务,10 个入口代表 10 条线程
串行队列 好比是 5 个人排成一支长队
并发队列 好比是 5 个人排成多支队伍,比如 2 队,或者 3 队。
同步任务 好比是管理员只开启了一个入口(当前线程)
异步任务 好比是管理员同时开启了多个入口(当前线程 + 新开的线程)

『异步执行 + 并发队列』 可以理解为:现在管理员开启了多个入口(比如 3 个入口),5 个人排成了多支队伍(比如 3 支队伍),这样这 5 个人就可以 3 个人同时一起穿过门禁了

『同步执行 + 并发队列』 可以理解为:现在管理员只开启了 1 个入口,5 个人排成了多支队伍。虽然这 5 个人排成了多支队伍,但是只开了 1 个入口啊,这 5 个人虽然都想快点过去,但是 1 个入口一次只能过 1 个人,所以大家就只好一个接一个走过去了,表现的结果就是:顺次通过入口

换成 GCD 里的语言就是说:

『异步执行 + 并发队列』就是:系统开启了多个线程(主线程+其他子线程),任务可以多个同时运行
『同步执行 + 并发队列』就是:系统只默认开启了一个主线程,没有开启子线程,虽然任务处于并发队列中,但也只能一个接一个执行了

参考链接:https://www.jianshu.com/p/2d57c72016c6

常量&变量 Constants & Variables

常量:值一旦设置就不能改变
变量:值可以改变
示例代码:

1
2
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

同时可以申明多个常量或变量,示例如下:

1
2
let a = "g", b = "k", c = "d"
var x = 0.0, y = 0.0, z = 0.0

注意:

若值不会改变则申明常量,若会改变则申明变量

类型注解 Type Annotations

当申明常量和变量的时候可以提供一个类型注解,来明确它们值的类型
类型注解:(在常量或变量名后加)一个冒号、空格和要使用的类型名
示例代码:

1
var welcomeMessage: String

申明同一类型的多个常量或变量,可以共用一个类型注解,示例如下:

1
var red, green, blue: Double

注意:

Swift拥有强大的类型推断,因此如果常量或变量有初始值,则不需要写类型注解

常量和变量命名 Naming Constants and Variables

非法的命名:不能数字开头或包含空格字符、数学符号、箭头、私有Unicode标量值、线和框绘制字符

注意:

如果命名要与Swift关键字相同,则需要使用反引号(‘)包围该关键字,但最好避免这样命名

打印常量或变量 Printing Constants and Variables

方法如下:
print(_:separator:terminator:) function:
分隔符和终止符参数有默认值,因此可以在调用此函数时省略它们。默认情况下,函数通过添加换行符来终止它打印的行。

字符串插值 string interpolation
在print函数中,用括号括起常量或变量名字,在括号前面用反斜杠转义
示例代码:

1
2
3
let name = "abner"
print("My name is \(name)!")
// Prints "My name is abner!"

注释 Comment

单行注视:两个斜杠(//)

1
// This is a comment.

多行注释:以斜杠和星号(/)开始,星号和斜杠(/)结束

1
2
/* This is also a comment
but is written over multiple lines. */

嵌套多行注释:使您能够快速而轻松地注释掉大块代码,即使代码已经包含多行注释。

1
2
3
/* This is the start of the first multiline comment.
/* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */

分号 Semicolons

Swift中不需要在每行末尾添加分号
但是在一行上写多个单独的语句时,需要分号分隔

整型 Integers

Swift提供8、16、32、64位的有符号或无符号整型

整型边界 Integer Bounds

调用整型的min或max方法可以获得整型的最小值或最大值
示例如下:

1
2
let minValue = UInt8.min  // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8

Int类型

在32位平台,Int的大小和Int32一致
在64位平台,Int的大小和Int64一致

UInt类型

在32位平台,UInt的大小和UInt32一致
在64位平台,UInt的大小和UInt64一致

注意:

除非需要UInt量级的数字,否则推荐使用Int,方便代码互相操作性

浮点数 Floating-Point Numbers

Swift 提供两种浮点数类型
Double:64位浮点数
Float:32位浮点数
Double至少精准到15位小数,Float至少精准到6位小数,当两者都可以使用时,推荐Double类型

类型安全和类型推断 Type Safety and Type Inference

类型安全:Swift是类型安全的,即要明确值的类型。Swift会在编译阶段进行类型检查来保证类型安全、
类型推断:Swift的类型推断使编译器在编译代码时可以自动推断出特定表达式的类型,只需检查提供的值即可

数字字面量 Numeric Literals

十进制浮点数:没有前缀
二进制浮点数:前缀为0b
八进制浮点数:前缀为0o
十六进制浮点数:前缀为0x

示例如下:

1
2
3
4
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation

十进制浮点数指数:E / e (可选)
十六进制浮点数指数:P / p (必须)
示例如下:

1
2
3
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

无论是整型还是浮点数,都可以加入“0”或者“_”来帮助阅读
示例如下:

1
2
3
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

访问修饰符

@private:只能在本类的内部访问
@protected:只能在本类或子类中访问
@package:只能在当前框架中访问
@public:可以在任意地方访问

真私有的属性:将属性定义在@implementation{}中,外界没有提示

Swift类型

Swift分为6种类型,它们分别是:class, struct, protocol, enum, functions, “Don’t care” type (generics)

class && struct

相同点:
stored var
computed var
constant let
functions
initializers

不同点:
| struct | class |
| —- | —- |
| 值类型:通过拷贝进行传递或赋值 | 引用类型:通过指针进行传递 |
| Copy on write | 自动引用计数 |
| 函数式编程:注重事物的功能性 | 面向对象编程:封装数据和函数到容器 |
| 没有继承 | 有继承:有唯一父类 |
| 构造器初始化所有变量 | 构造器不初始化变量 |
| 必须明确说明可变性:即必须用var声明 | 总是可变 |
| You “go to “ data structure | 用于特点情况 |
| 常见的struct: Int, String, Array, Dictionary | 常见的class:ViewModel |

protocol

精简的struct或class:有function和var,但没有具体实施
它是一个type:大部分protocol可以用在type可使用的地方
extension:通过protocol的extension去实施function

enum

离散值
Swift的enum有函数和计算变量
allCases: 可以遍历所有
Optional: 它是一个特殊的enum,有none和some(T)两个选项

functions

(parameterName: parameterType) -> returnType

generics

我们可能希望操作某个数据结构,但我们不在乎它是什么类型;但由于Swift是一个强类型语言,它必须有类型,因此我们使用泛型
例如:Array中的元素,Array 其中Element就是generics泛型