2ca603ec-0911-43b3-837f-becd2671a58e.png想念你的笑
想念你的外套
想念你白色袜子
和身上的味道
我想念你的吻
和手指淡淡烟草味道
记忆中曾被爱的味道
----For Swift
咳咳```一不小心唱起来了,味道。
说点实在的,Swift的味道还真是不得不让人迷醉。
三周之前,我不认识你,你不属于我;三周之后,我依然不认识你,你也不属于我。唯有的,只有我记住了你的一些味道:袜子味儿、辣椒味儿、火药味儿、无重复的味儿……当然,更多的,是清香味儿,来的轻盈,散的清凉。
容器
“Swift provides three primary collection types, known as arrays, sets, and dictionaries, for storing collections of values”
Swift 用来存储数据的三种类型:数组、集合、容器
- 数组
数组有三种最重要的运算:过滤、映射、缩减
let array = [2,24,56,96,68,88,44,37,1]
//1.过滤
let newarray = array.filter { $0 % 2 == 0}
print(newarray)//过滤奇数 [2, 24, 56, 96, 68, 88, 44]
//2.映射
let newArray2 = array.map { $0*$0}//每个对应平方
print(newArray2)//[4, 576, 3136, 9216, 4624, 7744, 1936, 1369, 1]
//3.缩减
let reduce1=array.reduce(0, combine: +)
print(reduce1)//416
- 集合
以hash code/哈希码/散列码 来存储数据,使用时很快就能找到其中某个数据的位置和值,型如:var a:Set<Int> = [1,1,5,4,2]
对集合的操作:
1.增删
a.insert(100) //添加元素
a.remove(1) // 删除元素
print(a) // [5, 100, 2, 4]
2.交并差子
var b:Set<Int> = [1,2,33,7]
print(a.intersect(b))//交集 [2]
print(a.union(b)) //并集 [2, 4, 5, 100, 7, 1, 33]
print(a.subtract(b)) //差集 [5, 100, 4]
var c:Set<Int> = [5,100]
print(c.isSubsetOf(a))//判断子集(Bool) true
- 字典
字典的每个元素都是由两个方面组成,冒号前是键,冒号后是值
通过键获取对应的值(可空类型,因为给的键有可能没有对应的值)
如:
var dict :[String:String] = ["abacus":"算盘","abnomal":"异常","hello":"你好","good":"好"]
print(dict["hello"]!) //你好
print(dict["sss"]) //nil
遍历字典
for value in dict.values{
print(value)
}
for key in dict.keys{
print(key)
}
for (key,value) in dict{
print("\(key)-->\(value)")
}
/*结果:
abnomal
shit
hello
good
abnomal-->异常
shit-->🐶💩
hello-->你好
good-->好
*/
枚举
两种相反的事物,我们义无反顾的选择Bool类型,那么超过两种但却又相互对立的事物,怎么描述呢?那么枚举就是必不可少的了。利用自定义的枚举类型,可以在项目中任意调用其中一种事件,比如,扑克有四种花色,利用枚举,就可以便捷的定义区分花色了
花色枚举
- Spade: ♠️
- Heart: ♥️
- Club: ♣️
- Diamond: ♦️
enum Suite:String{
case Spade = "♠️",Heart = "♥️",Club = "♣️",Diamond = "♦️"
}
……
……
let suites = [Suite.Spade, .Heart,.Club,.Diamond]
函数
swift中,函数也是一种类型,这也意味着函数可以作为常量或者变量的类型。
同理,函数可以作为另一个函数的参数或者返回值.
- 尾随闭包
闭包:就是Java和C#中的 lambda函数(lambda表达式)、JS中的匿名函数,C中的B look起相同作用的,他存在的意义是,实现代码的解耦合
毕竟,写代码的终极目的,高类聚,低耦合
闭包的形式为:
{ (parameters) -> return type in
statements
}
这里的return可以省略。如果函数的最后一个参数是闭包,可以写成尾随闭包的形式,也就是将闭包放到函数参数的圆括号外面写一对花括号中;如果函数后面有尾随闭包且函数的圆括号里没有参数,那么圆括号可以省。
尾随闭包
如果函数的最后一个参数是闭包。可以将该参数放到函数的花括号内,省略圆括号()
reversed = names.sort { $0 > $1 }
数组names降序排列。
$0表示第一个参数
$1表示第二个参数
- 递归调用
递归,指的就是一个函数直接或间接调用自身的方法,其条件为:
1.递归公式
2.收敛条件
简单举个例子,用递归方法可以算1-100的求和:
func sss(n:Int)->Int{
if n==1{
return 1
}
return n + sss(n-1)
}
这里的sss函数,两个分支,一个是当n!=1的时候,再次调用自身,就是计算100的函数要调用99的函数,99的函数需要调用98的函数……直到调用到1,直接返回1,即可求出结果。这里,递归公式就是函数的return n + sss(n-1),递归条件是,当n==1的时候,停止递归,返回 给上一次的递归结果1.
经典应用:汉诺伊塔
func hanluoita(n:Int,_ a:String,_ b:String,_ c:String)
{
if n>0{
hanluoita(n-1, a, c, b)
print("\(a)--->\(b)")
hanluoita(n-1, c, b, a)
}
}
hanluoita(5, "A", "B", "C")
类
物以类聚,人以群分。故名思义,类,就是具有相同的属性的一个概括。
定义一个类主要有四个步骤:
发现类
- 在对问题的描述中找名词和动词
- 名词会成为类或者类中的属性 动词会成为类中的方法
定义类
- 定义类可以创建新的类型,类名每个首字母大写;
- 数据抽象--找到和学生相关的属性(找名词)
- 初始化方法\构造方法--创建对象要使用的方法--constructor
- 行为抽象--找到和学生相关的方法(找动词)
变量定义在类里,叫属性;函数写在类里面,叫方法
创建对象
- 调用初始化方法
给对象发消息
- 通过给对象发消息来解决问题
面向对象
面向对象七原则:(为了实现高类聚、低耦合)
-
单一职责原则(SRP)
每个类应该专注于做一件事情哦 -
**开闭原则(OCP) **
面向扩展开放,面向修改关闭 -
依赖倒转原则(面向抽象编程, DIP)
实现尽量依赖抽象,不依赖具体实现爱人, 待周爱人而后为爱人
《墨子·取周》 -
**里氏替换原则(LSP) **
能用父类型的地方就一定可以使用子类型.超类存在的地方,子类是可以替换的白马, 马也, 乘白马, 乘马也
黑马, 马也, 乘黑马, 乘马也
娣, 美人也, 爱娣非爱美人也
盗, 人也, 恶盗非恶人也
《墨子·小取》 -
** 接口隔离原则(ISP)**
应当为客户端提供尽可能小的单独接口,而不是提供大的总的接口 -
合成聚合复用原则(CARP)
尽可能使用合成/聚合达到复用,尽量少用继承。原则:一个类中有另一个类的对象 -
迪米特法则(LoD)
一个软件实体应当尽可能少的与其他实体发生相互作用
继承
继承: 从已有的类创建新类的过程
提供继承信息的称为父类(超类/基类);得到继承信息的称为子类(派生类/衍生类)
通常子类除了得到父类的继承信息还会增加一些自己特有的东西
所以子类的能力一定比父类更强大.
继承的意义在于子类可以复用父类的代码并且增强系统现有的功能.
继承特点:
- 可以将子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
- 如果要将父类型的变量转换成子类型需要用as运算符进行类型转换
- 如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
- 如果不确定父类型的变量中是哪种子类型可以用as?尝试转换
- 定义方法参数类型的时候尽可能使用父类型(抽象类型).因为如果用父类型的参数调用方法时可以传入任意子类型对象
多态
同样的对象类型接收相同的消息(调用相同的方法),但是做了不同的事情 这就是多态(polymorphism)
实现多态的关键步骤:
- 方法重写 override (子类在继承父类的过程中对父类已有的方法进行重写, 而且不同的子类给出各自不同的实现版本)
父类有的方法子类可以重新实现 这个过程叫方法重写,需要在方法前添加override关键字.重写有时也被称为置换/覆盖/覆写 - 对象造型(将子类对象当成父类型来使用)
可以通过if+as?将父类型安全的转换成子类型然后再调用子类特有方法
一些技能GET ✔️
-
便利构造器
我们可以在一个类中定义多个初始化方法
便利初始化方法 / 便利构造器:
调用了其他的初始化方法的初始化方法
convenience init() {
self.init(x: 0, y: 0)
}
convenience init(point: (Double, Double)) {
self.init(x: point.0, y: point.1)
}
```
**指派初始化方法 / 指派构造器**:
被其他初始化方法调用的初始化方法
init(x: Double, y: Double) {
self.x = x
self.y = y
}
- **计算属性**
在定义类的属性的时候,有两种方式:
存储属性:负责存储变量的值
计算属性:负责将存储数据进行计算返回新的值,有get和set方法
如果不允许修改的变量,就没有set方法,通过私有的方法保护原来的值。
//存储属性
private var _name: String
private var _hp: Int
private var _mp: Int
//计算属性
var isAlive: Bool {
get { return _hp > 0 }
}
var name: String {
get { return _name }
}
var hp: Int {
get { return _hp }
set { _hp = newValue > 0 ? newValue : 0 }
}
var mp: Int {
get { return _mp }
}
- ** 扩展 **
如果在某个特定的应用场景中发现现有的类缺失了某项功能
那么可以通过扩展(extension)的方式现场添加这项功能
extension Point {
var cgPoint: CGPoint {
get { return CGPointMake(CGFloat(x), CGFloat(y)) }
}
}
比如我在画布画贝塞尔曲线的时候,需要把点的坐标转换为CGFloat,就可以现场添加一个函数实现功能。
- **运算符重载**
当我们自己定义的函数也需要进行计算的时候,我们又想直接利用系统的运算符号,那么就可以对系统的符号函数进行运输符重载(+、-、*、/、%、><……都是系统制定的一个函数)
//对小于符号进行重载
func <(one: Student, two: Student) -> Bool {
return one.name < two.name
}
重载后,可以直接调用<符号进行运算:
let stuArray = [
Student(name: "Wang Dachui", age: 24),
Student(name: "Lee Xiaolong", age: 49),
Student(name: "Zhang Nima", age: 18),
Student(name: "Guo Jing", age: 26)
]
// let newArray = stuArray.sort { $0.age > $1.age }
let newArray = stuArray.sort(<)
for stu in newArray {
print("(stu.name): (stu.age)")
}
输出以名字的首字母升序排列:
Guo Jin*: 26
Lee Xiaolon*: 49
Wang Dachu*: 24
Zhang Nim*: 18
* * *
环境果然促人成长,不知几个月后,是怎样的五味杂陈……
###嘿,s w i f t e r
![20160310231228_UduMR.jpeg](https://img.haomeiwen.com/i2670532/265efea2086917a7.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
网友评论