0%

算法复杂度分为时间复杂度空间复杂度

时间复杂度:指执行当前算法所消耗的时间
空间复杂度:指执行当前算法所需要占用的内存空间

时间复杂度

1
2
3
4
5
int i = 0,n=1000
i++
for (int i = 0; i < n; i++) {
i++
}

我们假设一行代码执行时长为1,那么总时长为2+n,这个算法的耗时随着n的增加而增加,用时间复杂度表示为:O(n)

常见的时间复杂度量级有:

  • 常数阶O(1)
  • 对数阶O(logN)
  • 线性阶O(n)
  • 线性阶对数O(nlogN)
  • 平方阶O(n²)
  • 立方阶O(n³)
  • n次方阶O(nⁿ)
  • 指数阶O(2^n)

常数阶O(1)

无循环的代码,执行一次就完了
1
2
3
int i = 0;
i++;
print(i);

对数阶O(logN)

执行时长成对数上涨
1
2
3
4
int i = 1;
while(i<n){
i = i*2;
}

线性阶O(n)

执行一下循环
1
2
3
4
int j = 1;
for(int i=1;i<=n;i++){
j+=i;
}

线性对数阶O(nlogN)

简单的线性+对数叠加
1
2
3
4
5
6
int j = 1;
for(int i=1;i<=n;i++){
while(j<n){
j = j*2;
}
}

平方阶O(n²)

两层循环
1
2
3
4
5
6
int m = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
m += i+j;
}
}

立方阶O(n³)

3层循环

m次方阶O(nⁿ)

n层循环

指数阶O(2^n)

递归函数执行时长
1
2
3
4
5
6
7
long aFunc(int n) {    
if (n <= 1) {
return 1;
} else {
return aFunc(n - 1) + aFunc(n - 2);
}
}

空间复杂度

空间复杂度算法包括:

  1. 程序本身所占的空间
  2. 输入数据所占的空间
  3. 辅助变量所占的空间

常数阶O(1)

与变量无关,具体固定的空间占用
1
2
3
for(int i = 1; i<=n ; i++){
i+=1;
}

线性阶O(n)

分配的空间与变量n相关,随着n的变化而变化
1
2
3
4
5
6
void fun(int n){
int a[] = new int[n]
for(int i = 1; i<=n ; i++){
a[i]=i;
}
}

设计模式分类

分类 概括
创建型模式 工厂模式
单例模式
建造者模式
原型模式
结构型模式 适配器模式
桥接模式
过滤器模式
组合模式
装饰器模式
外观模式
享元模式
代理模式
行为型模式 责任链模式
命令模式
解释器模式
迭代器模式
中介模式
备忘录模式
观察者模式
状态模式
空对象模式
策略模式
模板模式
访问者模式
J2EE模式 MVC模式
业务代表模式
组合实体模式
数据访问对象模式
前端控制器模式
拦截过滤器模式
服务定位器模式
传输对象模式

创建型模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

工厂模式

应用场景:发送网络请求时,通过不同字段获取不同的请求类型(GET POST PUT DELETE …)

单例模式

应用场景:一个App进程只有一个Application

建造者模式

应用场景:Retrofit通过建造者模式实现不同的回调方式,JSON解析方式等

原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
  1. 优点:性能高,逃避构造函数的约束
  2. 应用场景:JAVA中的Object clone()方法

结构型模式

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

适配器模式

应用场景:ListView,RecyclerView的Adapter使用,将数据与View的不同ItemType结合起来

桥接模式

将抽象部分与实现部分分离,使它们都可以独立的变化。

应用场景:需要将10种矩形与圆形与10种角色进行任意搭配绘制到画布上。星巴客卖咖啡:中杯、大杯、加大坏,可加入口味:牛奶、糖等

过滤器模式

应用场景:List的filter功能使用

组合模式

将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

应用场景:手机文件夹树状结构

装饰器模式

应用场景:ContextWrapper的封装,包装一个人:装上白皮肤是白种人,装上黑皮肤是黑种人,装上黄皮肤是黄种人。对象只是一个人

外观模式

隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。

应用场景:第三库的封装使用,提供给调用者尽量简单的访问接口

享元模式

减少创建对象的数量,以减少内存占用和提高性能。

应用场景:字符串池,Integer -128~127的装箱

代理模式

应用场景:Retrofit接口的请求,暴露给外面的是一个接口,使用动态代理去实现okhttp请求

行为型模式

这些设计模式特别关注对象之间的通信。

责任链模式

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

应用场景:App View的事件分发机制

迭代器模式

这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。

应用场景:JAVA数组集合的访问

中介者模式

这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。

应用场景:聊天室,统一发给中间平台,再由平台发送给指定用户。而不是用户与用户直接交流形成复杂交错的交互网

备忘录模式

保存一个对象的某个状态,以便在适当的时候恢复对象。

应用场景:Activity的onSaveInstanceState

观察者模式

一对多的通信

应用场景:RxJava

策略模式

一个类的行为或其算法可以在运行时更改。

应用场景:一个系统需要动态地在几种算法中选择一种。ContextWrapper的应用

Context概念

Context是一个抽象类,日常用的的具体实现有:Activity,Service,Application,占据了四大组件的三个<br>
Context:上下文,代表与操作系统交互的一种过程,Android在用户行为的过程中都需要Context参与,成为一个连通整个操作流程的媒介

content

ContextWrapper Context的装饰模式

内部的mBase是实际实现者,避免代码重复,版本兼容,根据传入者的具体类进入调用<br>
一般mBase 是通过 初始化或者#attachBaseContext实现赋值<br>
View#getContext 方法有可能返回ContextWrapper,Application,Activity
Application Activity Service ContentProvider BroadcastReceiver
Show a Dialog No YES NO NO NO
Start an Activity NO1 YES NO1 NO1 NO1
Layout Inflation NO2 YES NO2 NO2 NO2
Start a Service YES YES YES YES YES
Bind to a Service YES YES YES YES NO
Send a Broadcast YES YES YES YES YES
Register BroadcastReceiver YES YES YES YES YES
Load Resource Values YES YES YES YES YES

NO1 表示Application context的确可以启动Activity,但是它需要创建一个新任务,并产生一个不标准的回退栈(back stack),通常不推荐这样做。
NO2 表示这是非法的,但是这个填充(inflation)的确可以完成,但是是使用所运行的系统默认的主题(theme),而不是你app定义的主题。
NO3 在Android4.2以上,如果Receiver是null的话(这是用来获取一个sticky broadcast的当前值的),这是允许的。

Application 应用程序,app有且只有一个,生命周期即App的生命周期

Activity 应用程序的活动组件

Activity提供一个可供用户操作的可视化界面,存在自己的一套生命周期,通过"堆栈"的形式进行新建、显示、隐藏、销毁

Activity 生命周期

activity_lifecycle

Activity 启动模式

模式 说明
“standard” (默认模式) 默认。系统在启动它的任务中创建Activity的新实例,并将意图路由到该实例。Activity可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例。
“singleTop” 如果Activity的实例已存在于当前任务的顶部,则系统通过调用其onNewIntent()方法将意图路由到该实例,而不是创建Activity的新实例。Activity可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例(但只有当后端堆栈顶部的Activity不是Activity的现有实例时)。
“singleTask” 系统创建新任务并在新任务的根目录下实例化Activity。但是,如果Activity的实例已存在于单独的任务中,则系统会通过调用其onNewIntent()方法将意图路由到现有实例,而不是创建新实例。一次只能存在一个Activity实例。
“singleInstance” 相同”singleTask”,区别在于:系统不启动任何其他Activity纳入控制实例的任务。Activity始终是其任务的唯一成员; 任何由此开始的Activity都在一个单独的任务中打开。

taskAffinity 属性

taskAffinity 是在xml注册Activity时的属性,默认情况是Activity启动是放入与App包名相同的栈中,如果设置了android:taskAffinity 则会推入与taskAffinity相同的栈中,如果没有这个Activity栈则会创建一个<br>
taskAffinity 属性主要和 singleTask 或者 allowTaskReparenting 属性配对使用,在其他情况下没有意义

Intent flags 跳转意图

当进行Activity跳转时,可设置跳转意图,实现Activity与启动模式相同的效果
模式 说明
FLAG_ACTIVITY_NEW_TASK 与上述”singleTask” 效果相同
FLAG_ACTIVITY_SINGLE_TOP 与上述”singleTop”效果相同
FLAG_ACTIVITY_CLEAR_TOP 如果正在启动的Activity已在当前任务中运行,则不会启动该Activity的新实例,而是销毁其上的所有其他Activitys,并将此意图传递给Activity的恢复实例

Service 不可见服务

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件<br>
官网说可以在此执行耗时操作,实际发现 Service 是在ActivityThread 线程,执行耗时操作会导致 ANR ,耗时操作需要新建线程

Service 生命周期

service_livecycle

Service 启动方式

  1. startService()startForegroundService()onBind()方法可返回null,

    调用的生命周期: onCreate –> onStartCommand(可多次调用) –> onDestroy
  2. bindServiceonBind()方法需要返回一个IBinder的不可空对象。绑定到服务必须提供 ServiceConnection 的实现

    调用的生命周期: onCreate()->onBind()->Service running–>onUnbind() -> onDestroy()

HashMap简要

HashMap允许key和value都为null,非线程安全,无序的集合

储存方式

  1. 长度8以下为链表储存,8以上为红黑树
  2. 负载因子:当达到size*负载因子 时会进行扩容 2^n

LinkedHashMap简要

LinkedHashMap是继承 HashMap ,解决HashMap无序的问题,非线程安全

TreeMap简要

TreeMap 是有序的红黑树储存,key不能为空

常用的线程安全的Map

  1. ConcurrentHashMap 推荐,加锁
  2. SynchronizedMap 通过Collections#synchronizedMap获取
  3. HashTable 很少用到了

ArrayList简要

ArrayList 是实现了ListRandomAccess的顺序表,当容量不足时会自动扩容

特点:访问元素效率较高,操作元素效率低(每次add remove都会对整个表进行操作)

初始化

1
2
3
4
// 可自定义初始化储存数据的数组长度
ArrayList(initialCapacity)
// 使用默认数组长度,默认长度为0
ArrayList()

扩容机制

  1. 首次未设置数组长度时: 当执行add*添加数据会创建一个10个长度的数组
  2. 再次扩容:当执行add*时会检查是否有足够空间,没有的话则增加当前长度的一半n/2
  3. 减容:当执行remove*时,先获取数组当前位置的数据,整个数组从当前位置向前移动补位,
    置空数组后面的数据。(这里有个问题:减少容量时ArrayList里的数组长度没有减少,意味着数据长度只增不减)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 每次执行  add*  时会进行数组长度校验,如果数组长度不够则会添加原长度的 n/2
    private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
    }

线程安全问题

  1. 使用CopyOnWriteArrayList加锁的顺序列表
  2. 使用Collections#synchronizedList

LinkedList简要

LinkedList是实现了List``Deque的队列双向链表,每个节点包含了数据,上一节点和下一节点的信息,容量是动态非连续的

特点:插入、删除较快,不需要移动数据,只移动节点信息就可以了

初始化 LinkedList()

扩容机制 动态随数据长度

Vector简要

与ArrayList相似,区别:线程安全,可自定义每次扩容大小

Stack简要

继承Vector,线程安全,实现栈的功能

常用线程安全的 List,Set

  1. CopyOnWriteArraySet 获取的iterator()不支持remove set add操作
  2. CopyOnWriteArrayList 获取的iterator()不支持remove set add操作
  3. SynchronizedRandomAccessList 通过Collections#synchronizedList获取
  4. SynchronizedList 通过Collections#synchronizedList获取

综合对比

  • ArrayList的操作数据都是通过普通的数组实现,随机访问和修改元素比较快,但插入/删除等操作需要移动较多数据,比较适合在访问数据比较频繁的场景使用
  • LinkedList是双向链表,在随机访问和修改都需要先去查找节点,但是在插入/删除数据时不需要移动数据,比较适合用在插入/删除频繁的场景中。
  • LinkedList还实现了队列接口,通过头或尾进行顺序访问的同时可以删除节点,充分发挥了链表的优势。
  • Vector与Stack实现的线程安全,但也降低的效率

@objc 用于swift提供oc调用

  1. 在方法上加如

    @objc private func gotoLanguage(_ sender:UIButton){}

    因为Button加事件是OC调用 使用 btn.addTarget(self, action: #selector(self.gotoLanguage(_:)), for: .touchUpInside)

    数据类型 方法

    1. var 可变数据
    2. let不可变数据,常量
    3. typealias 给类型加别名 typealias joker = UIViewController
    4. as is String as NSString 转型 类型检查操作符 is let s = “joker”; if s is String {}
    5. inout 参见三,swift基础的方法
    6. lazy 懒加载
    7. static class 在func前加的关键字表示类型方法,都可以用于指定类方法.不同的是用class关键字指定的类方法可以被子类重写
    8. get{retrun value} set{newValue} 使用set 必须要用get 但是get 可以单独使用

      willSet { newValue} didSet {oldValue} set方法监听,不能与上面的共存,官方编译器不允许
    9. mutating 异变,结构体和枚举是值类型。默认情况下,值类型属性不能被自身的实例方法修改,mutating加在func前可进行修改
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      struct Point {    
      var x = 0.0, y = 0.0    
      mutating func moveBy(x deltaX: Double, y deltaY: Double) {   
           x += deltaX   
           y += deltaY    
      }
      }
      var somePoint = Point(x: 1.0, y: 1.0)
      somePoint.moveBy(x: 2.0, y: 3.0)
      print("The point is now at (\(somePoint.x), \(somePoint.y))")
      // prints "The point is now at (3.0, 4.0)"
      --------------------------------------------------------
      enum TriStateSwitch {    
      case off, low, high    
      mutating func next() {        
      switch self {        case .off:            self = .low        case .low:            self = .high        case .high:            self = .off        }    }}var ovenLight = TriStateSwitch.lowovenLight.next()// ovenLight is now equal to .highovenLight.next()// ovenLight is now equal to .off
  1. subscript 下标 下标脚本允许你通过在实例名后面的方括号内写一个或多个值对该类的实例进行查询, 如:someArray[index],someDictionary[key]

    自定义:get set可选,与类属性一样
    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
    subscript(index: Int) -> Int {
        get {        
    // return an appropriate subscript value here
        }    
    set(newValue) {        
    // perform a suitable setting action here
        }
    }
    --------------------------------------------------------
    struct TimesTable {
        let multiplier: Int
        subscript(index: Int) -> Int { 
           return multiplier * index
        }
    }
    let threeTimesTable = TimesTable(multiplier: 3)
    print("six times three is \(threeTimesTable[6])")
    // prints "six times three is 18"
    --------------------------------------------------------
    struct Matrix {
        let rows: Int, columns: Int
        var grid: [Double]
        init(rows: Int, columns: Int) {
            self.rows = rows
            self.columns = columns 
            grid = Array(repeating: 0.0, count: rows * columns)
        }
        func indexIsValid(row: Int, column: Int) -> Bool {
            return row >= 0 && row < rows && column >= 0 && column < columns
        }
        subscript(row: Int, column: Int) -> Double {
            get {
                assert(indexIsValid(row: row, column: column), "Index out of range")
                return grid[(row * columns) + column]
            }
            set {
                assert(indexIsValid(row: row, column: column), "Index out of range")
                grid[(row * columns) + column] = newValue
            }
        }
    }
    var matrix = Matrix(rows: 2, columns: 2)
    matrix[0, 1] = 1.5
    matrix[1, 0] = 3.2
    // 0.0 1.5
    // 3.2 0.0
  2. overide 重写var func class fuc subscript
  3. final 阻止子类对相应的属性,方法,下标等重写

语句

  1. switch 贯穿 fallthrough
  2. switch 分句检查 where
  3. 判断语句:1guard1 guard condition else{ statements; retrun} 与if语句类似,相比总有一个else语句

    else里面必需用returnbreakcontinue 或者 throw 返回

    它会让正常地写代码而不用把它们包裹进else 代码块,并且它允许你保留在需求之后处理危险的需求
  4. sdk版本号判定,系统新增 if #available(iOS 10, macOS 10.12, *) {}
  5. defer defer语句延迟执行直到当前范围退出
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    func processFile(filename: String) throws {
        if exists(filename) {
            let file = open(filename)
            defer {
                close(file)
            }
            while let line = try file.readline() {
                // Work with the file.
            }        
    // close(file) is called here, at the end of the scope.
        }
    }
    使用 defer语句来保证 open(_:)函数能调用 close(_:)
  1. 访问控制
    通过在实体的引入之前添加 `open` , `public` , `internal` , `fileprivate` ,或 `private`  修饰符来定义访问级别
    访问优先级如下:
    • open: 在Module内外都可以访问,继承,重载
    • public: 只在Module内可访问,继承,重载,外只能访问
    • internal :默认访问级别,本Module操作
    • fileprivate : 在当前swift文件里可操作
    • private :在当前类可操作

元组 Tuples

  1. 定义1:let info = (“joker”,100,true)
    info.0; info.1; info.2
  2. 定义2:let (name,age,good) = (“joker”,100,true)
    name, age, good
  3. 定义3:let info = (name:”joker”,age:100,good:true)
    info.name , info.age , info.good<br>

也可以定义用 _ 表示不关心该数据, 不能访问,元组的数据类型不能改变

结合关键字typealias比较好用

1
2
typealias namedFishesType = (first:Int, second:String, third:Bool)
let namedFishes: namedFishesType = (1, "tow", false)

元组判断 (使用下划线( _)来表明匹配所有可能的值)
1
2
3
4
5
6
7
8
9
10
11
12
13
let somePoint = (1, -1)
switch somePoint {
case (0, 0):   
 print("(0, 0) is at the origin")
case (_, 0):    
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:    print("(\(somePoint.0), \(somePoint.1)) is outside of the box")}

// prints "(1, 1) is inside the box"

控制流

  1. do-while换成了repeat-while 其它不变
  2. 各种 condition : condition语句可以不用括号包裹,如 :if i>10{ statements}
    condition只支持true or false  不再像oc支持判空或者判0 必须加以判定,如:if ob != nil {}      if  index != 0 {}
  3. switch语句,不再需要显式break语句,不再贯穿,如果需要贯穿则需要加关键字 fallthrough
    可用区间匹配  ...  ..< 
    复合情况  ,可用,分隔  case 1,3,5,6:
  4. 可选项绑定 (与一般if控制流有区别,if 后condition 必定是Bool)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let str = "12"        
    if let id = Int(str) {
    print("解析成功")
    }else{
    print("解析失败")
    }
    //普通if用法
    let str = "12"
    let id = Int(str)
    if id != nil {
    print("解析成功")
    }else{
    print("解析失败")
    }

?和!的使用和区别

问号?

  1. 声明时添加?,告诉编译器这个是Optional的,如果声明时没有手动初始化,就自动初始化为nil
  2. 在对变量值操作前添加?,判断如果变量时nil,则不响应后面的方法。

叹号!

  1. 声明时添加!,告诉编译器这个是Optional的,并且之后对该变量操作的时候,都隐式的在操作前添加!
  2. 在对变量操作前添加!,表示默认为非nil,直接解包进行处理

不确定类型

  1. AnyObject 可以表示任何类类型的实例。
  2. Any 可以表示任何类型,包括函数类型。

协议

  1. 协议可以放属性,子类可以继承修改 如:var nickName:String { get set}
  2. 协议可以放初始化方法

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

不同类型数据不能直接处理,需要转型

let i = 1; let j = 2.0;  let m = Double(i)+j;
也可直接定义 let i = 1 + 1.0 时,可以获取Double数据

运算符

  1. 位运算
    ~ 取反 &位与 |位或 ^位异 <<左移 >>右移
  2. 区间运算符
    1
    2
    3
    4
    5
    6
    7
    8
    1..<9  1到8    
    1...9 1到9
    list[...3] list 从0到3
    list[3....] list从到结束
    let range = ...3 0到3的PartialRangeThrough
    ```
    3,??
    两个?号后接默认值
    let list = [“1”,”2”]
    let s = list[3] ?? “3”
    1
    2
    3
    ```
    let img : UIImageView? = nil
    let icon :UIImage? = img?.image ?? UIImage(named: "xxx.png")

字符串

  1. “双引号”,与普通NSString一样

  2. “”” 三引号 “”” 可定义多行,可加双引号,注意:中间的空格号最后封闭有关

  3. 如果想转成熟悉的NSString用的话可以:let str = “”; (str as NSString).substring(to: 10)

  4. 字符串拼接

    1
    2
    3
    let string1 = "hello"let string2 = " there"var welcome = string1 + string2//  "hello there"
    var instruction = "look over"instruction += string2// “look over there"
    let exclamationMark: Character = "!""hello there”.append(exclamationMark)// "hello there!"
  5. 字符串插值

    1
    2
    3
    let multiplier = 3
    let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
    // "3 times 2.5 is 7.5"

定义和调用函数

  1. 定义:

    • 多个形参 func goodJoker(param:String,param2:String) -> [String:String] {return [param:param2]}

    • 复合返回 func goodJoker(param:String,param2:String) -> (v1:String , v2:String) {return (param , param2)}

    • 可空 如果返回的值可能为nil 则需要在返回值定义时后面加? 如 : (v1:String , v2:String)?

      类似 (String, String)?的可选元组类型和包含可选类型的元组 (String?, String?)是不同的。对于可选元组类型,整个元组是可选的,而不仅仅是元组里边的单个值
    • 参数标签 上面方法调用 self.goodJoker(param:”joker”, param2:”is good”) 每次调用都需要tag与OC一样

      也可以自定义`tag func joker(tag param:String)` 调用  self.joker(tag: "joker is good")<br>
      神奇的_    如果用下划线定义tag 则可以直接调用 self.joker("joker is good")
    • 参数默认值 OC中定义不同的参数传值需要定义多个方法,现在一个搞定
      func whoGood(_ who:String = "joker", is isGood:Bool = true) {}

      调用方式

      1
      2
      3
      self.whoGood("me") 
      self.whoGood(is:false)
      self.whoGood()
    • 可变形参

      1
      2
      3
      4
      5
      6
      7
      func test(numbers: Double...) ->Double {
      var total:Double = 0;
      for number in numbers{
      total += number
      };
      retrun total;
      }
    • 输入输出 inout: 函数能够修改一个形式参数的值,而且你想这些改变在函数结束之后依然生效,那么就需要将形式参数定义为输入输出形式参数 (记得加&)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      func swapTwoInts(_ a: inout Int, _ b: inout Int) {//两个参数值替换    
      let temporaryA = a    
      a = b    
      b = temporaryA
      }
      var someInt = 3
      var anotherInt = 107
      swapTwoInts(&someInt, &anotherInt)
      print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // prints "someInt is now 107, and anotherInt is now 3"
    • 函数类型: 函数也可以做为参数,返回值

      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
      func addTwoInts(_ a: Int, _ b: Int) -> Int {    
      return a + b
      }
      var mathFunction: (Int, Int) -> Int = addTwoInts// 作为参数

      ——————————————————————————————————————————————————

      func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {// 作为形式参数    
      print("Result: \(mathFunction(a, b))")
      }
      printMathResult(addTwoInts, 3, 5)
      // Prints "Result: 8"

      ——————————————————————————————————————————————————

      func chooseMath(_ p:Int) -> String {
      return "this parameter = \(p)";
      }
      func chooseStepFunction(_ method:(Int) -> String,_ p:Int) -> (Int,Int) -> Int {
      print(method(p))
      return addTwoInts
      }
      print("new result = \((chooseStepFunction(chooseMath,1))(3,5))")
      // this parameter = 1
      // new result = 8
      解读:上面分别将chooseMath作为参数将addTwoInts作为返回值,
      • 内嵌函数 在默认情况下在外部是被隐藏起来的,但却仍然可以通过包裹它们的函数来调用它们。

        包裹的函数也可以返回它内部的一个内嵌函数来在另外的范围里使用
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        func chooseStepFunction(backward: Bool) -> (Int) -> Int {    
        func stepForward(input: Int) -> Int {
        return input + 1
        }    
        func stepBackward(input: Int) -> Int {
        return input - 1
        }    
        return backward ? stepBackward : stepForward
        }
        var currentValue = -4
        let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
        // moveNearerToZero now refers to the nested stepForward() function
        while currentValue != 0 {    
        print("\(currentValue)... ")    
        currentValue = moveNearerToZero(currentValue)
        }
        print("zero!")
        // -4...// -3...// -2...// -1...// zero!

闭包 (与oc的blocks相似)

  1. 闭包语法

    1
    2
    3
    4
    5
    6
    7
    8
        { (parameters) -> (return type) in    
    statements  
    }
    例:
    var list = [1, 2]
    list.sort { (s1:Int, s2:Int) -> Bool in
    return s1>s2
    }
  2. 闭包捕获值

    一个闭包能够从上下文捕获已被定义的常量和变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍能够在其函数体内引用和修改这些值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    func makeIncrementer(forIncrement amount: Int) -> () -> Int {    
    var runningTotal = 0    
    func incrementer() -> Int {        
    runningTotal += amount        
    return runningTotal    
    }    
    return incrementer
    }
    let incrementByTen = makeIncrementer(forIncrement: 10)  
    incrementByTen()  //return a value of 10  
    incrementByTen()  //return a value of 20  
    incrementByTen()  //return a value of 30
  3. 闭包的循环强引用

    1
    2
    3
    4
    5
    6
    7
    8
    class ClosureCode {    
    var delegate :SubVideoMode?
    var nameStr = ""
    lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate] (index: Int, stringToProcess: String) -> String in
    return "print \(self.nameStr) \(index) \(stringToProcess)"
    }
    }
  4. 引用 weak 弱引用 与 unowned 无主引用 (不安全,无主引用假定是永远有值的,程序会尝试访问曾今存在过的内存地址)

    当两个对象分别强引用对方时,无法释放,需要关键字标记 (应用区别,加?可空的用weak,没有?不可空的用unowned

权举

  1. 定义
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //普通
    enum UserName{
    case joker
    case god // 也可以直接用,分隔 case joker,god
    }
    //定义不同类型值
    enum Species{
    case person(String,Int)
    case pig(Int)
    }
    //指定值
    enum Numbers{
    case zero = 0 , one ,two
    }
    //zero明确为0,后面的依次加1
    // Numbers.zero.rawValue 为0 如果定义时未给值刚为zero
    //可以通过原始值初始化 let num = Numbers(rawValue: 1) 获取的是Numbers.one
  2. 使用:

    可以直接以点开头,如:.joker 则是获取的是UserName.joker btn的属性 btn.setTitleColor(UIColor.white, for: .normal)

    不同类型值的使用
    1
    2
    3
    4
    switch species {
    case .persion(let name, let age):    print("person: \(name), \(age)")
    case .pig(let weight):    print("pig: \(weight).")
    }

六,类和结构休

  1. 定义
    1
    2
    3
    4
    5
    6
    class SomeClass {
    // class definition goes here
    }
    struct SomeStructure {
    // structure definition goes here
    }
  2. 类实例判断是否引用自同一个类实例 相同于(===) 不相同于(!==)
  3. convenience: convenience用来进行方便的初始化,就相当于构造函数重载。不能调用super.init 可以用self.init
  4. required:required 子类需要添加异于父类的初始化方法时,必须先要实现父类中使用required修饰符修饰过的初始化方法,并且也要使用required修饰符而不是override
  5. final 可以防止方法重写
  6. 可失败初始化器 init?{} 可以返回nil

错误处理

1
2
3
4
5
6
7
8
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}