数据库范式

1NF

列的原子性,列的内容不可再分割

学生表(学号、姓名、年龄、性别、地址)。地址可以细分为国家、省份、城市、市区、街道,那么该模式就没有达到第一范式。

  • 第一范式存在问题:冗余度大、会引起修改操作的不一致性、数据插入异常、数据删除异常。

2NF

非主键完全依赖主键
(确保每列都和主键直接相关)
(表必须有主键ID)

版本表(版本编码,版本名称,产品编码,产品名称),其中主键是(版本编码,产品编码),这个场景中,数据库设计并不符合第二范式,因为产品名称只依赖于产品编码。存在部分依赖。所以,为了使其满足第二范式,可以改造成两个表:版本表(版本编码,产品编码)和产品表(产品编码,产品名称)

3NF

  • 属性不依赖于其他非主属性
    (不传递依赖)
    不能存在非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
    (数据库中的一个表不包含已在其他表中已包含的非主关键字信息)
    (除主键以外的列,不存在某个列,能决定其他列)
    (确保每列都和主键列直接相关,而不是间接相关)

    订单表(订单编码,顾客编码,顾客名称),其中主键是(订单编码),这个场景中,顾客编码、顾客名称都完全依赖于主键,因此符合第二范式,但顾客名称依赖于顾客编码,从而间接依赖于主键,所以不能满足第三范式。如果要满足第三范式,需要拆分为两个表:订单表(订单编码,顾客编码)和顾客表(顾客编码,顾客名称)。

2NF和3NF的区别关键点

· 2NF: 非主键是否完全依赖于主键,还是依赖于主键的一部分
· 3NF: 非主键列是直接依赖于主键,还是直接依赖于非主键列

BCDF范式(鲍伊斯-科得范式,3NF改进形式)

  • 在第三的基础上, 数据库表中不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式
    防止主键的某一列会依赖于主键的其他列。当3NF消除了主属性对码的部分函数依赖和传递函数依赖称为BCNF。

特性:

1、所有主属性对每一个码都是完全函数依赖

2、所有主属性对每一个不包含它的码,也是完全函数依赖

3、没有任何属性完全函数依赖与非码的任何一组属性

库存表(仓库名,管理员名,商品名,数量),主键为(仓库名,管理员名,商品名),这是满足前面三个范式的,但是仓库名和管理员名之间存在依赖关系,因此删除某一个仓库,会导致管理员也被删除,这样就不满足BCNF。

4NF

非主属性不应该有多值。如果有多值就违反了第四范式。4NF是限制关系模式的属性间不允许有非平凡且非函数依赖的多值依赖。

用户联系方式表(用户id,固定电话,移动电话),其中用户id是主键,这个满足了BCNF,但是一个用户有可能会有多个固定电话或者多个移动电话,那么这种设计就不合理,应该改为(用户id,联系方式类型,电话号码)。

如果只考虑函数依赖,关系模式规范化程度最高的范式是BCNF;如果考虑多值依赖则是4NF

5NF

第五范式属于最终范式,消除了4NF中的连接依赖,第五范式需要满足以下要求:

1、必须满足第四范式

2、表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键。

一般实际应用中不必考虑第五范式。

JavaScript高级编程

什么是JavaScript

1.2 JavaScript实现

$$
完整的JavaScript实现 \left { \begin{matrix} ECMAScript(核心) \DOM(文档对象模型) \BOM(浏览器对象模型) \end{matrix} \right.

$$

  • ECMAScript: 由ECMA-262定义并提供核心功能
  • DOM:提供与网页内容 交互的方法和接口
  • BOM:提供与浏览器 交互的方法和接口.

1.2.2 DOM

Document Object Model 是一个API,用于在HTML中使用扩展的XML.DOM将整个页面抽象为一组分层节点,HTML或者XML页面的每个组成部分都是一种节点,包含不同的数据.

1
2
3
4
5
6
7
8
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<p> Hello World! </p>
</body>
</html>
1
2
3
4
5
6
7
graph LR
A[html] --> B[head]
B --> C[title]
C --> D[Sample Page]
A --> E[body]
E --> G[p]
G --> H[Hello World!]

DOM 通过创建表示文档的树,让开发者可以随心所欲地控制网页的内容和结构.使用DOM API,可以轻松地删除、添加、替换、修改节点.

HTML中的JavaScript

2.1 < script >元素

八个属性:

  • asyn

    可选,表示应该立即开始下载脚本,但不能阻止其他页面动作.只针对外部脚本文件有效.

  • charset
  • crossorigin

    可选,配置相关请求的CORS(跨资源共享)设置,默认不使用CORS. =“anonymous”请求不必设置凭据标志. =“use-credentials”设置凭据标志.

  • defer

    可选.表示脚本可以延迟到文档完全被解析和现实之后再执行.只针对外部脚本文件有效.

  • integrity

    可选.允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI, Subresource Intergrity).如果接收到的资源的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行.可以用于确保CDN不会提供恶意内容.

  • language (废弃)
  • src

    可选,表示包含要执行的代码的外部文件.

  • type

    可选,代替language,表示代码块中脚本语言的内容类型.

项目重构

数据结构设计

摒弃原来的多层结构,只用一层数据结构设计,并且使用relationships 关系

account设计(兼顾账户和第二类型)

  1. accountID

  2. balance(余额)

  3. counted

  4. icon

  5. name

  6. note

  7. type

    1. 支出
    2. 收入
    3. 普通账户
    4. 信用账户
    5. 投资账户
    6. 借贷账户
  8. billingData: 账单日 credit

  9. creditLimit: 额度 credit

  10. repaymentDate: 还款日 credit

  11. rate: 百分比:利息什么的 installment , loan

  12. autoCalculate installment, loan

  13. installmentType : installment, loan

  14. destinationAccount : loan

  15. installmentTimes: 期数 loan

  16. installmentType: 年月日 loan

  17. isDEBJ: 等额本金 loan

  18. isMoneyIn: 进、出 loan

  19. person: 借贷对象 loan

  20. state: 是否结清 loan

  21. timesInterest: 单次利息 loan

  22. timesLeft: 剩余期数 loan

ios 读取csv文件

最终代码

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
      
.fileImporter(isPresented: $imported, allowedContentTypes: [.delimitedText], allowsMultipleSelection: false){ result in
do {

guard let fileUrl: URL = try result.get().first else {return}

if (CFURLStartAccessingSecurityScopedResource(fileUrl as CFURL)) { //不在这个if里就出错,唉
//理由:iOS的沙盒机制保护需要我们申请临时调用url的权限

guard let data = String(data: try Data(contentsOf: fileUrl), encoding: .utf8) else { return }


handleSSJdataCSV(data: data)
//done accessing the url
CFURLStopAccessingSecurityScopedResource(fileUrl as CFURL)
}
else {
print("Permission error!")
}
} catch {
// Handle failure.
print ("error reading: \(error.localizedDescription)")
}
}

//数据格式处理代码
func handleSSJdataCSV(data : String){
var csvToStruct = [SSJdata]()

//split the long string into an array of "rows " of sata. each row is a string
//detect "/n" carriage return , then split
var rows = data.components(separatedBy: "\n")

let columnCount = rows.first?.components(separatedBy: ",").count
//remove the header rows
rows.removeFirst()

//loop around each row and split into columns
for row in rows{
let csvColumes = row.components(separatedBy: ",")
if csvColumes.count == columnCount{
let genericStruct = SSJdata.init( raw: csvColumes)
csvToStruct.append(genericStruct!)
}

}
print(csvToStruct)

for singleRecord in csvToStruct{
print(singleRecord.recordType)
}
//done accessing the url
}

参考文献:
https://stackoverflow.com/questions/67731694/how-do-i-save-an-imported-file-name-as-string-after-importing-file-in-swiftui

1
2
3
4
5
//不太管用
let fileUrl = try res.get()
self.fileName = fileUrl.lastPathComponent // <--- the file name you want

let fileData = try Data(contentsOf: fileUrl)

https://betterprogramming.pub/importing-and-exporting-files-in-swiftui-719086ec712
有大用
https://github.com/acwright/ImportExport
上面那个链接内容的示范工程

SwiftUI页面跳转

  1. TabView

    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
    36
    37
    struct ContentView: View {
    @State private var selection : Tab = .home
    enum Tab {
    case home
    case journal
    case statistics
    case settings
    // case test
    case test2
    }
    var body: some View {
    TabView(selection: $selection){
    HomeView()
    .tabItem {
    Label("主页", systemImage : "house")
    }
    .tag(Tab.home)
    ViewJournal()
    .tabItem {
    Label("流水", systemImage:"newspaper")
    }
    .tag(Tab.journal)

    ViewStatistics()
    .tabItem {
    Label("统计", systemImage:"waveform.path.ecg")
    }
    .tag(Tab.statistics)

    ViewSettings()
    .tabItem {
    Label("设置", systemImage:"seal")
    }
    .tag(Tab.settings)
    }
    }
    }
  2. NavigationLink

    1
    2
    3
    4
    5
    6
    7
    8
    NavigationView {
    VStack {
    NavigationLink(destination: Text("点击后显示的视图内容")) {
    Text("可点击内容")
    }
    }
    .navigationBarTitle("这是顶部标题")
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    NavigationView {
    List(0..<3) { i in
    NavigationLink(
    destination: Text("点击列表页后进入的页面 (i)")) {
    Text("列表序号 (i)")
    }
    }
    .navigationBarTitle("标题")
    }
  3. sheet向上拉起

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import SwiftUI
    struct ContentView:View {
    var body: some View{
    TestSheet()
    }
    }
    struct TestSheet: View {
    @State private var popoverIsShown = false
    var body: some View {
    Button("显示 Sheet") {
    self.popoverIsShown = true
    }
    .sheet(isPresented: self.$popoverIsShown) {
    RandomSheet(popoverIsShown: self.$popoverIsShown)
    }
    }
    }

    struct RandomSheet: View {
    @Binding var popoverIsShown: Bool
    var body: some View {
    Button("关闭") { self.popoverIsShown = false }
    }
    }
  4. ActionSheet

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Button("显示Sheet页") {
    showingSheet = true//点击后改显示
    }
    .actionSheet(isPresented: $showingSheet) {
    ActionSheet(
    title: Text("你想在这个页面放点啥?弹出一个提示,还可以修改信息等操作"),
    message: Text("如果要关闭此页只需要向下滑动或者点击下面的按钮..."),
    buttons: [.default(Text("关闭此面"))]
    )
    }
  5. popover

popover是一个专用的修改器来显示弹出窗口,在iPadOS上它显示为浮动气球,而在iOS上则像一张纸一样滑到屏幕上。

要显示弹出窗口,您需要某种状态来确定该弹出窗口当前是否可见,但仅此而已–与警报和操作表不同,弹出窗口可以包含所需的任何视图。因此,只要将您需要的任何东西放在弹出窗口中,SwiftUI就会处理其余的工作。

例如,当点击一个按钮时,将显示一个弹出视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentView: View {
@State private var showingPopover = false
var body: some View {
Button("显示菜单") {
showingPopover = true
}
.popover(isPresented: $showingPopover) {
Text("你要的内容在这里!")
.font(.headline)
.padding()
}
}
}

  1. alert
    1
    Alert(title: Text("弹出的标题!"), message: Text("这是消息的内容"), dismissButton: .default(Text("OK")))

参考资料:
http://www.neter8.com/ios/127.html