协议
协议是方法的集合(计算属性相当于方法)
可以把看似不相关的对象的公共行为放到一个协议里
协议的三种作用
1.能力-遵循了协议就意味着具备了某种能力
2.约定-遵循了协议就一定要能实现协议中的方法
3.角色-一个类可以遵循多个协议,一个协议也可以被多个类遵循,遵循协议就意味着扮演某种角色,遵循多个协议就以为着可以扮演多种角色
说明:Swift中的继承是单一继承(一个类只能有一个父类),如果希望一个类具备多种能力可以使用多个协议来实现。(c++里面是通过多重继承来实现的,并不好)
依赖倒转原则(面向协议编程)
1.声明变量的类型时应尽可能使用协议类型
2.声明方法参数类型时应尽可能使用协议类型
3.声明方法返回类型时应尽可能使用协议类型
开闭原则
1.抽象关键:在设计系统的时候一定要设计好模式
2.封装可变性:桥梁模式-将不同可变因素封装到不同的继承结构中
接口隔离,协议隔离原则
协议的设计要小而专不要大而全
协议的设计也要高度内聚
复合开闭原则
协议中全是抽象概念(只有声明没有实现)遵循协议的类可以各自对协议中的计算属性和方法给出自己的实现版本,这样当我们面向协议编程时就可以把多态的优势发挥到淋漓尽致,可以写出更通用更灵活的代码
例子:打折协议
/**
* 打折策略协议
*/
protocol DiscountStrategy {
/**
- parameter price:原价
- returns:折扣的金额
*/
func discount(price:Double) ->Double
}
///百分比折扣策略
class PercentageDiscount:DiscountStrategy {
var percentage:Double
init(percentage:Double){
self.percentage = percentage
}
func discount(price:Double)->Double{
return price*(1-percentage)
}
}
class FixedDiscount:DiscountStrategy {
var fixedMoney:Double
init(fixedMoney:Double){
self.fixedMoney = fixedMoney
}
func discount(price: Double) -> Double {
return price >= fixedMoney ? fixedMoney:0
}
}
class SegmentedDiscount:DiscountStrategy {
func discount(price: Double) -> Double {
if price < 20{
return 0
}else if price<50{
return 3
}else if price < 100 {
return 10
}else{
return 30
}
}
}
//图书
class Book {
var name:String
var price:Double
var type:String
//四人帮设计模式-策略模式
var strategy:DiscountStrategy?
/**
初始化方法
- parameter name: 书名
- parameter price:间隔
- parameter type:类型
*/
init(name:String,price:Double,type:String){
self.name = name
self.price = price
self.type = type
}
/// 减了多少钱
var discountValue:Double{
get{
if let s = strategy{
return s.discount(price)
}else{
return 0
}
}
}
///折扣后的价格
var discountedPrice:Double{
get{return price - discountValue}
let booksArray = [
Book(name: "C语言程序设计", price: 24.0, type: "计算机"),
Book(name: "名侦探柯南", price: 98.5, type: "漫画"),
Book(name: "Swift从入门到精通", price: 35.8, type: "计算机"),
Book(name: "黄冈教学密集卷", price: 34.2, type: "教材"),
Book(name: "中国股市探秘", price: 58.5, type: "金融")]
let discountDict:[String:DiscountStrategy] = [
"计算机" : PercentageDiscount(percentage:0.78),
"教材" : PercentageDiscount(percentage:0.85),
"漫画" : SegmentedDiscount(),
"科普" : FixedDiscount(fixedMoney:2)
]
var totalprice = 0.0
var totalDiscount = 0.0
for book in booksArray {
if let strategy = discountDict[book.type]{
book.strategy = strategy
}
print("《\(book.name)》原价:¥\(book.price)元")
print("《\(book.name)》折扣后:¥\(book.discountedPrice)")
totalprice += book.discountedPrice
totalDiscount += book.discountValue
}
print(String(format:"总计:¥%.1f元",totalprice))
print(String(format:"总计:¥%.1f元",totalDiscount))
计算机的硬件构成
运算器,控制器,存储器,输入设备,输出设备
运算器+存储器=cpu(中央处理器)
存储器=内存(Ram - random access memory)
程序员可以使用的内存
1.堆(Stack)- 我们创建的对象都是放在堆上的
2.栈(heap)- 我们定义的局部变量临时都是放在栈上的
3.静态区域(static area)
- 数据段--全局量
- 只读数据段--常量
- 代码段--函数和方法
值类型和引用类型的区别
1.结构的对象是值类型,类型的对象是引用类型
值类型在赋值的时候会在内存中进行对象拷贝
引用类型在赋值时的时候不会进行对象拷贝只是能加一个引用
2.结构中会自动生成初始化方法
3.结构中方法默认情况下是不允许改变结构中的属性的,除非加上Mutating关键字
自动内存处理机制
class Person {
var name :String
var age:Int
// 指派构造器(designated)
init(name:String,age:Int){
print("创建人")
self.name = name
self.age = age
}
//将构造器转化为必要构造器
//子类里必须遵循父类构造
// required init(name:String,age:Int){
// print("创建人")
// self.name = name
// self.age = age
// }
//默认赋值,便利构造器(convenience)
//只能横向调用,不能跨类
convenience init(){
//下面的语句必须写在调用自己的初始化方法之后否则MAJOR属性会被附上不正确的值
self.init(name:"无名",age:20)
}
deinit{
print("销毁人")
}
}
class Student:Person {
var major:String
// //重写
// override init(){
// self.major = major
// print("创建学生")
// }
init(name:String,age:Int,major:String){
//子类只能调用直接父类的构造器
//只能调用非便利构造器(指派构造器)
self.major = major//1初始化自己特有的属性
super.init(name: name, age: age)//2初始化二阶段
//此处可以调用对象方法,已完成初始化
}
func study(){
}
//释放时不需要传参
deinit{
print("销毁学生")
}
}
class Teacher: Person {
// override init(){
// print("创建老师")
// }
override init(name:String,age:Int){
super.init(name: name, age: age)
}
deinit{
print("销毁老师")
}
}
////创建一个学生对象,然后用stu去引用它,所以此时学生对象引用计数为1
////只要有一个对象引用,就不会删除,销毁(及时性销毁优于andrid)
//var stu:Student? = Student()
////取消全部引用就会销毁
////stu=nil
////此处没有创建新的学生对象,原来的学生对象的引用计数+1
//var stu2 = stu
////同上,原来的学生对象的引用计数+1
//var stu3 = stu2
////学生对象引用计数-1
//stu=nil
////学生对象引用计数-1
//stu2=nil
////学生对象引用计数-1
//stu3=nil
////当学生对象引用计数为0时ARC会自动清理内存释放学生对象
////ARC及时性的内存清理 优于JAVA中Garbage collection(垃圾回收)
//var stu1:Student? = Student()
////弱引用,虽然引用,但不会增加引用计数 默认是强引用(会增加引用计数)
//weak var stu2 = stu1
//
//weak var stu3 = stu2
//
//stu1=nil
////如果想释放内存,释放内存最好方式是手动将一个引用赋值为nil
//而这里是全局变量,函数调用不会使其消失
//var stu:Student?
//
//func foo(){
//// //局部变量,函数调用结束后局部变量就消失了
// //所以学生对象的引用计数也就变成0了,所以会被ARC释放掉
//// let stu = Student()
// print(stu)
//}
//
//foo()
//栈 -FILO 先进后出结构
//创建任何子类对象的时候一定是先创建父类对象
//var stu:Person = Student()
////如果一个引用转移了(会导致原来对象的引用计数-1 新对象引用计数+1)
////栈存储,先进后出
//stu = Teacher()
//stu = Person()
//超出自动释放池不会起作用
//var stu:Student?
//swift自动释放池
//通过向AUTOreleasepool函数中传入一个闭包来实现
//autoreleasepool { () -> () in
// //自动释放池中的对象引用在池的边界引用计数会自动-1的消息
// //将来做IOS开发时,如果某个地方会创建很多的临时对象
// //那么最好在此处设置一个自动释放池避免内存顺时峰值过高
// let stu = Student()
// let stu2 = stu
//}
//// 离开自动释放池时,Stu会受到引用计数减1消息,Stu2也会受到引用计数减1得消息
//OC用法
//@autoreleasepool
//双向关联关系
//如果程序中出现了类与类之间双向关联,必须要将其中一端设置成weak引用,否
//则将会形成循环引用,导致ARC无法释放内存
class Emp {
//推荐使用
//如果允许可控类型通常用WEAK来破除循环引用
//如果员工关联的部门对象被释放了那么dept会被赋值为NIL
//如果要继续给dept发消息不会崩溃
//weak var dept:Dept?
//谨慎使用
//如果不允许使用可空类型就必须使用UNOWNED来破除循环引用
//需要注意的是如果员工对象关联的部门对象被释放了
//如果还要通过员工对象操作它所关联的部门对象将导致程序崩溃
//错误提示EXE_BAD_ACCESS
var dept:Dept?
init() {
print("创建一个员工")
}
deinit{
print("销毁员工")
}
}
class Dept {
weak var manager : Emp?
init(){
print("创建一个部门")
}
deinit{
print("销毁部门")
}
}
//func bar() {
// _ = Person()
// let emp = Emp()
// let dept = Dept()
// //引用计数无限,破除环可解除环,方法WEAK
// emp.dept = dept
// dept.manager = emp
//}
//
//bar()
////视图闭包
//var x :(Int,Int)->Bool = {
// [weak self](x,y) -> Bool in
// return true
//}
泛型
//通用版 类型为虚拟类型(泛型)
func mySwap<T>(inout a:T,inout _ b:T){
let temp = a
a=b
b=temp
}
//swift自动推断类型
var a="字符",b="坠马"
mySwap(&a, &b)
print(a,b)