1、范型
范型所解决的问题
函数、方法、类型:类,结构体,枚举,元组类型,协议
参数,返回值,成员函数参数,成员属性
类型不确定, 就用一个范型, 可以根据实參指定的类型,动态改变类型
在 函数的名字后面 用尖括号表示
在 类型的定义 类型名字后面, 用尖括号表示
范型函数
返回类型是范型
传入参数是范型
类型参数
占位类型
命名类型参数
类型参数 是有一个描述性名字的
Dictionary<Key,Value>
范型类型
类型: 枚举,类, 结构体,元组
类型 定义的时候,使用范型, 表示,它的属性成员,函数成员, 中定义的类型, 不是特定的,而是可以通过实參来指定
扩展范型类型
扩展一个范型类型时, 原始类型中声明的范型类型占位符,在扩展中可以使用这些类型占位符。不需要重新定义
类型约束
正是由于,类型不是固定的,可以随便指定的。 实际中, 我们并不要求是任意的所有类型,
而是要求类型,有一定的限制。
什么限制? 要求类型符合: 某协议,某协议组合, 继承自某父类
这是类型限制,
还有 : 取值的大小有一定的范围
怎么表示约束呢?
范型函数 约束 表示方法:
用分号:
范型类型 约束表示方法:
用分号:
关联类型
协议中的属性、方法, 可以使用范型类型,
不需要协议名后面加尖括号范型, 而是在协议的定义中
用关键字:associatedtype 范型类型占位符 的一条语句来实现。
如果某个, 结构体,类,枚举, 定义为需要实现该协议。
可以在类型的定义中,typealias指定 协议中的associatedtype关联类型指定实际的类型的名称
扩展:让一个 已经存在的类型 符合某个协议
extentesion Array: MyCoustomSomeeeeProtocol {}
protocol MyCoustomSomeeeeProtocol {
func printHllo()
}
where子句
func afaf<T:sommetype, Q:asdfasType
where T.asdf == Q.asdf,
T.asdfasdf:HelloClass
(aaa:T, bbb:Q) -> (T, Q) {
}
函数
闭包
闭包:传入一个闭包。
闭包实现体中,闭包接受者、传递闭包者
1, 读取这个参数。 闭包接受者,把创建好的参数传入闭包,给闭包读去使用
使用场景是: alamofire 的闭包, uploadTaskWithRequest的闭包
通常这个参数是struct类型
2, 修改这个参数。 传递闭包者, 把从接受者那里拿到的参数, 通过一定的滤斗行为, 修改这个值。 接受者,后面会从新拿回被传递者处理过的参数。
使用场景是:snapkit、sqlite.swift
通常这个参数是class类型
闭包表达式
尾随闭包
值捕获
闭包是引用类型
非逃逸闭包
自动闭包
//do-catch
//try?
//try!
//do-catch 模式
do {
let a = try tryGetString(false)
print(a)
} catch let a {
let a = a as! MyError
switch a {
case .ErrorGet(let block):
block("Hello")
default:
logFlag()
}
}
do {
let a = try tryGetString(true)
print(a)
} catch {
let error = error as! MyError
switch error {
case .ErrorNetWork(let code, let reson):
print(code, reson)
default:
print("asd")
}
}
if let b = try? tryGetString(true) {
print(b)
}
logFlag()
//let _ = try! tryGetString(true)
logFlag()
func tryGetString(let test:Bool) throws -> String {
//写在可能抛出异常的语句前面,defer才可能被执行。
defer {
logFlag()
}
if test {
throw MyError.ErrorNetWork(code: "404", reson: "asdf")
} else {
throw MyError.ErrorGet(block: { (a:String) in
print(a)
})
}
defer {
logFlag()
}
defer {
logFlag()
}
defer {
logFlag()
}
return "s"
}
func tryGetStringGo() throws {
try tryGetString(true)
}
let seprator:String = "================="
func logFlag(let file:String = #file , let line: Int = #line, let funcname:String = #function) {
print(file, line, funcname, separator: seprator, terminator: "************")
}
try
错误处理
表示、 抛出错误
表示错误:ErrorType
throw 跟 return一样 不涉及解除调用栈
func getSmting()throw{
if a {
return “ok”
} else {
//throw 立即退出方法
throw a:ErrorType
}
}
处理错误
try?
try!
try : 必须处理这个错误
1,传递给调用这个try的函数:继续传递
func getAd()throws{
if let a = try getSmting() {
}
}
2,用do,catch
do {
try let a = getAd()
if a ! = nil {
}
} catch {
error
}
do {
try 表达式
语句
} catch{
error常量
}
do{
try 表达式
//如果没有抛出错误,下面的语句执行,否则转移到catch子句
语句
} catch 模式 {
} catch 模式2 where 条件 {
} catch {
}
3,将错误做为可选类型处理
let a:String?
a = getSmting()
if a {}
try?
4,断言此错误不会发生
有时候你知道throwing函数是不会抛出错误的
这种情况下,可以在表达式前面 写try!来禁用错误传递
这会把调用包装在一个有错误抛出的运行时断言中。
如果真的抛出错误,你会得到一个运行时错误
禁用错误传递
try!
指定清理操作
使用defer语句,在即将离开当前代码块执行的语句
该语句可以执行清理工作
不论是因为return离开、break离开、throw离开,
都可以执行defer中的语句
延迟到当前的作用域退出之前,这个语句的要求是
不能包含任何控制转移语句。比如break、return、throw
扩展语法
类,结构体,枚举,协议
如果写了扩展,则改类型 所有实例都可以用, 不管扩展的代码 写在 类型声明前面还是后面
属性, 类型属性: 只能是计算型的
不可以添加存储型。 不可以为已有属性添加观察器
类型属性、 类型方法 都不能被重写。 所以只能用static, 不管是struct,还是class,enum的类型属性、类型方法
struct aa {
class func aa(){}//errr:只能用static
}
struct aa{
class
}
类类型 的 存储属性不能 用class关键字, 因为class 关键字表示属性可以被重写, 然而类类型的存储属性 无论如何不能被重写, 所以要用static
类类型 可以用 static存储型属性 , 可以用计算型属性。
但是存储属性 不能被子类重写。所以存储属性要用static
实例方法、类型方法: static: 添加新的功能,不能重写已有的功能
可变实例方法:
mutating
extension Int{
mutating func square(){
self=self*self
}
}
定义下标:
定义和使用新的嵌套类型:
使用一个已有类型 符合 某个协议:
构造器
提供新的构造器:
为类添加 便利构造器
不能添加 新的指定构造器, 指定构造器和析gou qi
逐一成员构造器、指定构造器、默认构造器、便利构造器
构造器规则- 让所有成员完全初始化
方法
下标
嵌套类型
协议
类、结构体、枚举 符合 协议
协议语法
类、结构体、枚举 定义非常相似
父类放在前面, 协议放在后面
属性要求
声明属性 可读写
类型属性、类型方法, 用 static关键字
计算型、 存储型、 观察器、 下标,
常量计算型(没有常量计算型,因为计算型的值都是不确定,要加var, 计算型变量都是var的)、
变量计算型(只要是计算型, 都加var)、
只读计算型(get)
常量存储型
变量存储型
只读存储型(就是常量存储型)
结论: 协议总是用var来声明 属性。 类型后面加上{get set}可读可写,{get}可读
没有计算型常量:计算型变量只实现get方法
存储型变量、存储型常量、计算型变量
存储型常量=》计算型变量,实现get方法的计算型变量代替
属性要求,存储型,计算型。 无法获知。采纳协议时,可以定义为存储型变量 或者 计算型变量
协议 类型属性
协议中定义类型属性, 总是 使用 static关键字做为前缀,
类类型采纳协议时,可以使用class关键字来声明类型属性。
方法要求
协议中定义类方法, 总是 使用static关键字做为前缀,类类型采纳协议时,可以使用class关键字来做为前缀
类:
类型属性:
static , class
存储变量,存储型常量, 计算型变量
类型方法:
static, class
存储变量,存储型常量, 计算型变量
实例属性:
存储变量,存储型常量, 计算型变量
实例方法:
mutating方法要求 变异方法
在实例方法中修改值, 在结构体,枚举中,将mutating关键字做为方法的前缀, 写在func关键字前,表示该方法 可以修改 任意属性的值
构造器要求
init
协议做为类型
做为函数、方法、构造器中的参数类型 或 返回值类型
做为常量、变量、属性的类型
做为数组、字典、其他容器中的元素类型
协议也是一种类型。 协议类型的名称 应与 其他类型 的写法相同, 使用驼峰式写法
委托模式
通过 扩展 添加协议一致性
这里说的不是 扩展协议。
扩展协议,可以提供默认的实现:必须提供
也可以不提供默认的实现? 不可以
某个类,本来没有声明为符合某个协议,
然而,这个类,把它进行扩展, 在扩展中,声明为符合某个协议,
与这个类,直接声明为符合某个协议
作用是相同的。
扩展协议:扩展 方法、下标、属性、构造器
原来的协议
通过 扩展 采纳协议
protocol TextRepresentable {
var texualDescription:String
}
struct Hamster {
var name:String
//实现了协议要求的方法,却没有声明采纳协议
var texualDescription:String {
return “asdfasdf”
}
}
//空扩展体 来采纳协议
extension TextRepresentable {}
协议类型 的集合
协议的继承
协议可以继承其他的协议
就跟类一样,一个类可以继承其他的类
一个类,可以采纳其他的协议
类类型 专属 协议
protocol SomeClassOnlyProtocol : class, SomeInhreieitProtocol {
//这里是类类型 专属协议的定义部分
}
只能让类 来采纳 该协议, 结构体, 枚举 不能采纳该协议
协议合成
let adfa: protocol<somapra, anotherpro>
局部作用域有效的,临时的协议
协议合成, 协议继承 ?
函数传递过程的可选解包
可选类型 就是 类型后面加? , 或者!
参数为 一个 可选类型,或者一个语句块中定义的一个变量为 可选类型。
加!,使用变量时 会强制解包, 如果为nil则运行时错误。
如果不加?,! ,这个参数或变量,不能nil,没有初始化的值不能赋值
除非是定义为可选
所以,swift的好处是 如果一个函数, 或者闭包, 参数类型后面没有?,!不是可选的, 那么这个
参数是一定不会为nil的。因此可以放心使用
条件绑定一定要是对可选变量进行解包
把一个可选类型 -》 类型: 解包
可选类型 -》 可选类型: 不会触发解包
检查 协议一致性
is: 是否符合协议
as? 符合时,返回实例, 否则返回nil
as ! 符合时返回实例, 失败时,crash
as? , as! 强制转换以后 ,绑定到实例时,
那个实例, 仅仅是 符合 协议类型的实例, 其他的属性不可以被访问和打印
可选的 协议要求
整个函数类型是可选的, 不是函数的返回值可选
可选的协议要求 只能用在标记了@objc的协议中
@objc protocol CoutnaerDataSource {
optional func adsfa(coutn:Int)->Int
optional var fixedIncrement:Int {get}
}
协议扩展
提供默认实现
协议本身来实现功能。 协议 ,不是 一堆的 方法、属性、下标、构造 后面没有赋值,也没有花括号吗?
协议本身来实现 方法、属性、 下标、构造
protocol RandmNumberGenerator {
func rundom()->Float
}
extension RandomNumberGenerator {
func randomBool()->Bool {
return random() > 0.5
}
}
通过协议扩展, 所有采纳协议的类型, , 都能获得这个扩展所增加的方法实现。
如果 扩展的协议, 被某一个类所采纳, 这个类,自己实现了 扩展中的协议要求,
那么,它自己实现的, 将会替代扩展中的 默认实现
协议扩展 提供了默认的实现, 采纳了这种协议的类, 因为有了默认的实现, 但是它却是又 声明了,需要实现协议的要求, 然后协议所要求的 属性、 方法、 下标 都在默认中被实现了,
因此 , 这些要求 , 可以不需要类 去实现。 和 可选的协议一样:
有要求, 但是可以实现要求, 可以不实现要求,
那么区别是? 提供默认实现的协议扩展要求,和协议中声明的可选要求 ,有什么区别?
optional声明的要求:可选链式调用
在扩展中默认实现的要求:直接调用
为协议扩展添加限制条件
//where子句
extension CollectionType
where Cdfadf.element:
TextaereTalbe
{
var asdfDesrpt:String {
}
}
扩展collectiontype协议, 只适用于
集合中的元素采纳了textrepresentable协议的情况
where Generator.Element: TextRepresentable
把逻辑 和 行为 分开--》协议
值类型
String,Array和Dictionary类型均以结构体的形式实现。这意味着被赋值给新的常量或变量,或者被传入函数或方法中时,它们的值会被拷贝。
NSString,NSArray和NSDictionary类型均以类的形式实现,而并非结构体。它们在被赋值或者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用。
闭包是引用类型
方法命名
at, in, on, during, for
over,above,below,before,after,
with, through,except, but
as for, according to along with, ashore
since,util,
“等价于”表示两个类类型(class type)的常量或者变量引用同一个类实例。
恒等
//用值类型
“等于”表示两个实例的值“相等”或“相同”,判定时要遵照设计者定义的评判标准,因此相对于“相等”来说,这是一种更加合适的叫法。
用struct,enum,tuple,string,array,dictionary
1,要用==运算符来比较实例的 数据 时
2,两个实例的拷贝 能 保持 独立的状态 时
3,数据被多个线程 使用 时
可以在线程之间安全的传递变量,而不需要特地去同步,不需要花功夫来防范其他代码在暗地里修改它们
用class
1,共享的 可变对象时
2,==来比较实例 身份的 时
参数名和类型,外部名称,内部名称
有意在初始化时设置为空的
override 重写构造器
override
required子类必须实现该构造器
父类的必要的 构造器 , 可以不需要添加override修饰符
属性
存储型属性:
常量结构体的存储型属性:无法修改该实例的任何属性
延迟存储属性
lazy:
1、实例的构造过程结束后,才会知道影响值的外部因素时,可以使用lazy
2、获得属性的初始值需要复杂 或 大量 计算时, 可以只在需要的时候计算它。
计算型属性
只读计算属性:只有getter,没有setter
必须使用var关键字定义计算属性。 包括只读计算属性。
因为他们的值不是固定的。let用来声明常量,表示初始化后,再也无法修改的值。
全局变量
在函数、方法、闭包 或 任何类型之外定义的变量
局部变量
在函数,方法,闭包内部定义的变量
类型属性
计算型类型属性,
static var adf:String{
get{return “asdf”}
set(value){afsdfa = value}
}
存储型类型属性,
staic var sdfChannles:Int = 10
只读计算型类型属性,
static var adf:String{
get{return “asdf”}
}
只读存储型类型属性:
static let asdf = 1
计算型、
存储型、
延迟存储属性、 不需要加lazy,它本身就是延迟初始化的,
什么是延迟: 在被访问的时候,才会初始化。即使是多个线程同时访问,
系统也保证对其进行一次初始化
如果是局部变量,局部的存储型属性,加了lazy,延迟存储属性,没有被初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次
观察器、
lazy延迟存储属性
计算属性本身就是延迟属性
可以为 存储属性 添加属性观察器,设置默认值时不会被触发。
不需要为 延迟存储属性添加观察器,不需要为 计算型属性添加观察器。
但是 如果 是继承过来的包括存储型 和 计算型, 可以添加观察器
默认值、
赋值语句
构造器
便利构造器
可失败构造器
继承
定义一个基类
子类生成
重写
实例方法、 类方法 都可以重写
如果不写override,编译将会不通过,报错
凡是重写的属性, 都可以提供getter,setter,或者添加willset/didset观察器
计算型必须是var,只读计算型,是只提供getter
存储型可以是let,var,只读存储型,是加let
加let的存储型属性, 子类继承它时,重写let的只读存储型属性,提供getter,setter
只要提供getter,setter,属性就不能加let关键字,也就是说 父类只读的let 存储型的属性,重写时,不能提供getter,setter
重写getter,setter, 一般是对父类的var 存储型属性、 计算型属性 进行重写
防止重写
final
存储型属性的 初始化
存储型属性的值不能处于一个未知的状态
自定义构造过程
构造参数、
可选属性: 在初始化的时后设置为空
常量属性,构造时,指定一个值. 一旦常量属性被赋值, 它将永远不可更改
常量属性,只能在 定义它的类的构造过程中修改, 不能在子类的 构造过程中修改
默认构造器
没有父类、所有属性都有默认值, 自动生成一个构造器
值类型的构造器代理
便利构造器: 就是init里面可以调用init
类 类型 : 指定构造器、 便利构造器
类的继承和构造
两段式构造?
指定构造器必须总是向上代理
便利构造器必须总是横向代理
可失败构造
init?()
return nil
init?(rawValue:){}
用一个非可失败的构造器 重写了父类的可失败构造器
感叹号! 问好?
!:对应类型的隐式解包可选类型
必要构造
隐式解包可选类型
重写父类的必要构造器时, 不需要加override
闭包或函数 设置默认值
用闭包为属性提供默认值。 没有参数的闭包
{[weak self] (dfasdf:String, asdf:Int) in
asdfasdf = asdfasdf
return asdfasdf
}()
{[weak self] in
asdfasdf = asdfasdf
return asdfasdf
}()
{[weak self]
asdfasdf = asdfasdf
return asdfasdf
}()
表示立即执行此闭包
不能在闭包里面访问其他属性。即使这些属性有默认值。 也不能使用self,
不能调用任何实例方法
!
required
用闭包为属性提供默认值 用 “ = ”
仍然是存储型属性
let add:String = {return “asdfasdf”}()
计算型属性
let add:String {get {return “11”}
set(value) {
staff = value
}}
可失败构造器
init?(asdfa:String) {
if da.isEmpty() {return nil }
self.asdfasd = asdfa
}
一旦构造失败 , 就会触发断言
init!(adfa:String){
if adfa.isempty() {return nil}
self.asdf = adfa
}
构建一个对应类型的 隐式解包可选类型 的对象。
? 可选链式调用 访问 可选字符串类型String?
自动赋值为nil
用闭包 为属性 提供默认值
闭包的 返回值 赋值
闭包本身 的 赋值
任何缺少override关键字的重写都会在编译时被诊断为错误。
使用关键字 final 来禁用子类重写
final var
final func
final class func
final subscript
防止重写
class添加final,整个类 标记 为final, 这样的类不可以被继承
你不可以将一个继承来的读写属性重写为一个只读属性。
如果你在重写属性中提供了 setter,那么你也一定要提供 getter。如果 不想写getter, 可以再getter中 ,直接返回 super.someproperty
setter > getter
可选链式调用:在当前值可能为nil的可选值上 请求和调用 属性、方法、下标的方法。
如果可选值有值,调用成功;如果可选值是nil,那么调用 将返回nil。
多个调用连接在一起,形成一个调用链,如果其中任何一个节点为nil,整个调用链都会失败,整个调用链返回nil
!:强制展开,如果失败,就会crash
?:可选调用,如果失败,就会返回nil
使用?代替!
为可选链式调用 定义模型类
?访问属性
?调用方法
?访问下标
多层可选链式调用
在方法的可选 返回值 上进行可选链式调用
js.residence?.address = “asdfa”
可选链式调用失败时,等号右侧的代码不会被执行
johoo.residence?[0]
弱引用,或无主引用,以替代强引用,从而解决循环强引用的问题
var dictionary = [“dave”:[2,3123,4], “bev”:[123,3,45,1]]
dictionary[“dave”]?[0] = 123
dictionary[“bev”]?[2] = 12
dictionary[“adsfafds”]?[2] = 123
在方法的圆括号后面加上?
if let beginWithThe = joho.residence?.address?.buildingIndetifer()?.hasPrefix(“”) {
if begintWithThe {
} else {
}
}
在方法的返回值上 进行 可选链式调用, 而不是方法本身
1,弱引用, a,b 都是?可选的
一个人不总是有房子,一个房子不总是有人住在里面
2,无主引用, a必须有b,b不一定有a
一个人可能有、或者没有信用卡, 但是一张信用卡总是关联着一个客户
3,隐式解析类型, 无主引用: a,b,都不能为nil
每个国家必须有首都,每个城市必须属于一个国家
隐式解析可选类型的属性 在类型结尾处 加上感叹号City!的方式,将country的capitalCity属性声明为隐式解析可选类型的属性。 capitalcity属性的默认值为nil,但是不需要展开它的值就能访问它
Person和Apartment的例子展示了两个属性的值都允许为nil,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。
Customer和CreditCard的例子展示了一个属性的值允许为nil,而另一个属性的值不允许为nil,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为nil。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
闭包引起的循环强引用问题,
解决方法,还是使用 weak, 或者 unowned
如果被捕获的引用绝对不会变为nil,应该用无主引用,而不是弱引用。
lazy属性, 只有当初始化完成 以及 self 确实存在后,才能访问lazy属性。 因此闭包中, 可以用self
闭包捕获列表 [unowned self, weak deleate = self.delegate]
某一个对象持有闭包, 闭包体里面 使用了这个对象self, 这样互相持有,两个对象就产生了循环强引用
lazy var jj:(Int,String) -> String = {
[unowned self, weak delegate = self.delegate!] (index:int, stringtoProcess: String) -> String in
闭包的函数体 语句
}
lazy var someClusre:Void -> String = {
[unowned self, weak delegate = self.delegate!] in
闭包的函数题语句
}
无主引用、
弱引用: 总是可选类型。 当引用的实例被销毁,弱引用的值会自动为nil
无主引用:同时销毁
当引用计数为0时,销毁实例
创建实例的强引用。 强: 它将实例牢牢保持住,只要强引用还在,实例是不允许被销毁的
隐式解析
显示解析?
函数, 方法 , 闭包 内部定义的变量--局部变量
全局变量, 存储型变量
延迟存储属性 lazy,
全局的变量 本来就是 延迟计算的, 不需要加lazy
先写 父类名, 在写 协议名
protocol Fullynamed {
var fullName:String {get}
}
var a = Int
var a = Double
var a = [“1”, “2121”,”12312”]
begin . . . end
var shotpis = Int
shapes[1…3] = []
var letters = Set<Int>()
var letters:Set<String>
Array<Int>()
Int
Int,String,Int
Int:String,String:Int
枚举:
关联值
原始值
成员值
枚举
枚举值
原始值: 字符串, 字符, 整型, 浮点型
初始值
关联值:
递归枚举
1,关联值 存储在枚举成员中, 2, 原始值 存储在枚举成员中,
==》 枚举值
使用整数作为原始值, 隐式赋值, 依次递增1
第一个枚举成员, 原始值 为0
使用字符串做为枚举类型的原始值时, 每个枚举值成员的隐式原始值 为 该枚举成员 的名称
使用原始值 初始化 枚举 实例
enum ad : Int{
case a, b, c , d
}
if let a = ad(rawValue:1)? {
switch a {
case .a:
case .b:
case .c:
case .d:
default:
} else {
}
oc枚举,枚举值只能是整型:int、unsigned int,long,long long、int32_t、int64_t、nsinteger
swift枚举
1、是集合类型,值类型
2、枚举成员,可以关联任意类型:string、array、int、dictionary、double、float,struct、class、元组、函数类型、闭包类型
关联值-在switch case分支中使用let或var前缀,提取每个关联值;如果一个枚举成员的所有关联值都被提取,可以把let放在成员名称前面, 括号面的每一个关联值省略let或者var
3、跟class一样,有构造方法、析构方法,还可以遵循协议
4、用在switch分支语句中,必须穷举所有枚举值
5、枚举成员不会提供默认值,本身就是完备的值:可以使用原始值填充成员
6、枚举值可以递归: 某一个成员的关联值类型是枚举类型自身,在这个成员类型的定义前面加上 indirect关键字
enum asdf{
case asdfa
case asdf2
case asdfasdf(fads:String,fadsf:int)
case asdfdf(dfad:String)
}
asdf.asdfa(“asdfas”,”asdfasdf”)
let asdff = asdf.asdfasdf(fads:“fads”,fadsf:”fsdfasdf”)
switch asdff {
dase .asdfa
case .asdf2
case .asdfasdf(let a, let b)
print (a)
print (b)
case .asdfdf(let c)
print (c)
}
元组
1,
git
//github
//gitlab
svn
try? hell()
try! hell()
throws写在箭头前面
do catch
func fudd() throws -> String{
return
}
do {
//expression: 表达式
try expression
statements
} catch pattern 1 {
//匹配模式
statements
} catch pattern 2 where condition {
statements
}
将错误转换成可选值, try?expression时, 一个错误被抛出,那么表达式的值就是nil.
下面x,y 有着等价的含义
func sometthorwingFunction() throws->String {}
let x = try? sometthorwingFunction()
let y:String?
do {
y = try sometthorwingFunction()
} catch {
y = nil
}
func fetchData()->Data?{
if let data = try ? fetchDataFromDisk() {return data}
if let data = try ? fetchDataFromServer() {return data}
return nil
}
禁用错误传递, 如果真的抛出了错误, 则会在运行时发生错误
let photo = try!loadimge(“./asdfasdf/df.jpg”)
当前作用域退出之前执行
func processFile(fileName:String)throws {
if exists(filename) {
let file = open (filename)
defer {
close(file)
}
//try? ,不需要catch。 返回nil, try!不需要catch,运行时错误 try:立即抛出一个错误
while let line = try file.readline() {
}
}
}
如果一个或者多个条件不成立,可用 guard 语句用来退出当前作用域。
guard语句格式
guard 条件 else {
//条件 可以使用可选绑定, 条件的结果必须符合booleantype协议
语句
guard绑定的值 guard语句后面可以使用
guard let a = asfOptional else {return}
print(a)//a可以使用
//必须有else子句,而且在子句中 标记 noreturn特性的函数,或者使用return, break, continue, throw
退出作用域
}
强制展开 触发运行时错误
可选 可选链式调用
可选的
强制的
可选链式调用失败时, 后面的 调用 不会 执行
嵌套类型 加前缀 加上 外部类型的类型名作为前缀
可选链 , 强制展开
?, !
?返回nil, 可选展开
!如果是nil ,则触发 运行时 错误, 因为没有展开的值
都可以用数组字面量
1、数组字面量 创建数组
[Int]
Array<Int>()
2、集合
[1,2,3,4] 可以是数组或者集合
3、字典
字典字面量 创建字典
[Int:String]
Dictionary<Int,String>()
[“a”:”adsf”,”asdf”:”1231”]
扩展,
1, 类, 结构体, 枚举, 协议
添加新的功能
2,
计算型属性、
计算型类属性
实例方法、 类方法
新的构造器
定义 和使用 新的 嵌套类型
支持 新的 一个 或 多个 协议
mutating, 改变 实例
func dfasd(a:protocol<UITableViewDataSource, UITableViewDelegate>, b:String)
extension CollletctionType
数组的遍历
索引值 和 数据值 组成的元组
元组 分解成 临时常量 或者变量 来进行遍历
for (asdf,asdfd) in somearray.enumerate() {
}
1,闭包是引用类型
闭包 作为 参数 传递
闭包是在 函数 返回后 才被执行
从函数中逃逸
@noescape,不允许逃逸
可以使用self
闭包的生命周期 就在 函数里面。
func adf(@noescape closure()->Void){
closure()//确保在add调用后就没有用了
}
sort方法 传递 一个闭包参数, 在排序结束之后就没用了
escape允许逃逸出函数作用域
var a:[()->String] = []
func collectA(@autoclosure(escaping) pp:()->String){
//pp并没有调用, a在函数作用域范围外, 函数返回之后被调用,
允许逃逸出函数作用域
a.append(pp)
}
collectA(array.removeAtIndex(0))
collectA(array.removeAtIndex(0))
for aa in a {
aa()
}
2,自动闭包
自动创建的闭包, 用一个普通的表达式 来 代替 显示的闭包
statements 表达式 会被返回
这种闭包不接受任何参数、当它被调用的时候,会被返回被包装在其中的表达式的值。
用普通的表达式 来 代替显式的闭包,从而省略闭包的{}花括号
自动闭包的好处就是节省内存吧?
fatalError(“1g bytes”)并没有分配 1g的内容存储。其实就存储了一个闭包使用的时候才会被调用
a(“dfadf”)
等价于
a( void -> void in { return adfadf } )
显示的闭包{(params) -> returnType in statements}
in可以省略
返回类型可以省略、参数名称可以省略(使用缩写)、直接用一个运算符、
尾随闭包 可以省略小括号、
let add = {array.removeAtIndex(0)}
这个闭包 并没有执行
只有当调用 add()才会执行
延时求值
@autoclosure
() -> String
{ somefunc(asdfa) }
fatalError(@autoclosure message:()->String){}
fatalError(“HEllooooo”)
fatalError({ (Void) -> Void in “hellowoooo”})
{
(params) -> returnType in
statements
}
闭包, 根据上下文推断类型,({s1, s2 in s1 > s2})
参数重 使用参数名的缩写, 则参数可以省略, 返回类型可以省略, 直接写函数体names.sort({$0 > $1})
使用运算符函数 names.sort(>)
尾随闭包
闭包可以在被定义的上下文中, 捕获常量 或 变量
func makeIncremeter(amount:Int) -> () -> Int {
var runingttoal = 0
func incremter() -> Int {
runingttoal += amount
return runingttoal
}
return incremter
}
let a = makeIncremeter(4)
let b = makeIncremter(12)
a()
b() //12
let c = b
c() //24 函数 和 闭包 都是引用类型。
一个没有参数,并且返回值为string的函数()->String{}
let a = {
print(“adsfadsfa”)
}
//并不会打印adsfadsfa
a()
这时候打印
var cutomersInline = [“asdf”,”asdfasfd”,”asd”]
func saveCustomer(customerProvider:()->String){
customerProvider()
}
saveCustomer({customersInline.removeAtIndex(0)})
func saveCustomer(@autoclosure customerProvider:()->String){
customerProvider()
}
//自动转化为一个闭包
saveCustomer(customerInline.removeAtIndex(0))
3,@autoclosure(escaping)
{
(s1:String,s2:String) -> String in
return “asdfa”
}
闭包的写法:
1,上下文 推断 类型
{s1, s2 -> Int in return 1 }
2,单表达式隐式闭包, 省略return关键字
{s1, s2 in s1 > s2}
3,参数名称 也可以缩写
{$0 > $1}
4,>,省略了参数, 省略了返回值, 省略了return,大括号也省略了
names.sort(>)
5,{(a:String,and:Int) -> Void in print(“asdfa”)}
6,{[unowned self] (a:String,and:Int) -> Void in print(“afasdfasdfa:(self.name)”)}
尾随闭包,
函数的最后一个参数 是 闭包类型。
调用这个函数
func somefun(cll:()->Void){}
func somefun(cll:()->()){}
somefun(){}
somefun({})
somefun{}
func somefunc(s:String, ff:()->Void){}
somefunc(s:”asdfa”,{})
somefunc(s:”asdf”){}
func hell(add:String…) -> String{
}
参数是一个元组, 返回值 也是 一个元组
0个 或 多个
func hell(ads:String…) -> (asdf:String,adds:Int) {
for aasdf in ads {
}
}
一个函数 最多 只能有一个 可变参数
闭包做函数的参数
函数做函数的参数
闭包捕获列表
lazy var asdf:Void->String = {
self.name
}
lazy var asdf:Void->String = {
[unowned self, weak delegate = self.delegate!] in
这里是闭包函数题
}
func asHtml()->String{
}
a.asdf()
a.ashtml()
swift的权限控制 与 继承 无关, 是单纬度的。
因为 swift的主要需求是:将一个类、 框架 的实现细节 隔离保护起来。
1,objc的扩展和swift的扩展?
扩展: 为一个已有的类、 结构体、 枚举、 协议 添加新功能
swift的扩展没有名字
使用static 来定义类型属性。
存储型属性 不能 作为类方法, 不能用static, class
存储型类属性, 用static, 子类不能重写
计算型类属性, 用static不能重写, 用class可以重写
为类 定义 计算型 的类型属性, 可以改用关键字 class 来支持 子类对父类 的实现 进行重写。
计算型类型属性
static var add:Int {return 1}
static var ad:String = “123123”
class var add:Int {return 1}
AddClass.add = 1213
AddClass.ad = 123123
实例方法、 类方法
class func asdfa(){}
构造器
下标
可变实例方法
给self赋值
定义和使用 新的嵌套类型
扩展 符合 某个协议
2,扩展 和 继承 、扩展 ?
扩展 可以为一个类型添加新的功能, 但是不能重写已有的功能
扩展 不能 重写 已有的功能
协议
方法、 属性、下标
类、结构体、枚举 都可以采纳协议
[]
[AnyObject]
1、一个任意类型对象的数组
2、任意类 类型
3、类,枚举,结构体,函数,闭包
Any 函数类型, 非类类型
is 检查类型
as 转换类型
检查 一个 类型 是否实现了 某个协议
@objc
标记 @objc特性 的协议 , 只能 被 继承子 objc 类的子类
其它的类、结构体、枚举 不能采纳这种协议
switch表达式的case中 使用 is 和 as 操作符
Any 或 AnyObject
空的元组:(), Void
func adfMean(asdf:Double…)->Double {
}
func ad(ads:Int…) -> (a:String,b:String)? {
for str in ads {
}
if true {
return nil
}
return (“123”,”ads”)
}
默认参数值
默认值 的 参数 放在最后, 非默认参数的顺序是一致的
\0
\
\t
\n
\r
\”
`
\’
\u{222f9abcd}
Character
override
重写属性、方法、重写下标
在重写定义的前面 加上 override关键字。
重写属性观察器
计算型属性 和 和属性观察器
计算型属性不能用let
计算型属性:提供setter和getter方法。前面加var关键字
只读计算型属性:去掉setter方法,但是前面的var关键字不能省
延迟存储型属性:前面加layer
存储型属性:去掉layer
属性观察期:使用关键字willset,didset 后面 加花括号
全局变量:
var gloableString:String = "asdfadf"
只读计算型全局变量:
var gloableString2:String {
get {
return "asdfas"
}
}
var gloableString3:String = {return "asdfa"}()
不能加lazy:下面编译错误
lazy var gloabelString4:String = "asdfasdf"
class add {
let adfa:String {
return “asdfasdf”
}
}
case add {
var adfa
var ad:String {
get {
return “asdfasdf”
}
set (asdf) {
adfa = asdf
}
}
}
存储属性添加属性观察器
延迟
intrinsic
1, 函数 , 闭包 , 区别
函数作为参数传递
闭包作为参数传递?
@autoclosure 自动闭包
@noescape 非逃逸闭包
行參中的闭包默认是逃逸的:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
undefineEscapeFunc {
print("hellooo")
}
let aAction = handlers.first!
aAction()
return true
}
typealias aBlockType = ()->()
var handlers = aBlockType
func undefineEscapeFunc(a:()->()){
handlers.append(a)
}
@autoclosure(escaping)
1、为协议扩展 添加限制条件。限制条件 写在 协议名 之后, 使用where子句来描述
数组 符合 collectiontype协议, 而数组中的元素 又符合 textrepresentable协议
extension collectiontype where generator.element:textrepresentable {
}
2、类型约束
c1必须符合container协议, c2必须符合container协议,c1的itemtype 必须 和c2的itemtype类型相同]
func allitemsMatch <c1:container, c2:Container where c1.itemtype == c2.itemtype, c1.itemtype:equatable> (somecontainer:c1,_ anothercontainer:c2)->bool{
}
0..<numberOfSections
类型、表达式、语句、声明、特性、模式、范型参数
枚举
枚举关联值
枚举原始值
递归枚举:indirect
枚举 本质上 就是 用来 描述数据的。 是某种数据的 一种 描述形式,它本身不需要有计算。
空合运算符
let a:String ?
let b:String = “asdfasd”
a != nil ? a! : b
a = a ?? b
闭合区间
a…b
for index in 1…5 {
print(index)
}
半开区间
a..<b
for i in 0 ..< count {
}
func afads(numbers: double … ) -> Double {
var totoal:Double = 10
for number in numbers {
totaol += number
}
return totoal / double(numbers.count)
}
访问控制
模块 和源文件、
访问级别、
访问控制语法:public,internal,private
自定义类型:
元祖、 函数、 枚举、 嵌套
类类型:
如果想为 一个 自定义的类型, 指定访问级别
如果将类型 指定为private,那么这个类型的所有成员,都为private
如果将类型 指定为public,或者internal,或者不指定的,默认是internal,它的成员默认是internal
元祖:(var name:String, var sex:String,var idno:String) ?
(public var name:String, internal var sex:String, private var idno:String)
函数类型:
private func somefunction()->(someinternalclass, someprivateclass){}
枚举:
public enum compasspoint{
case north
case south
}
以最低级别的访问权限为准
可以通过 重写 为继承来的类成员 提供更高的访问级别。
类A 的私有成员 外部不能访问
public class A {
private func someMthoed(){}
}
类B,继承类A,可以重写类A的私有方法, 因为类B的实现跟类A在同一个源文件里面。
它把类A的私有成员拉升到高一级别的访问权限了, 给外部的文件访问类B的方法
internal class B: A {
override internal func someMthoed(){}
}
类型 变量
不能定义一个public级别的属性,但是它的类型却是private级别的 变量
getter, 和setter
stuct trackedstring {
var numberofeidits = 0
private(set) var adfa = 1
private(get) var adf = 12
}
构造器
可以低于 等于 所属类的类型 的访问级别。必要构造器 必须和所属类型的访问级别相同
默认构造器的访问级别与所属类型的访问级别相同。但是如果类型的访问级别是public,则它的默认构造器的
访问级别是internal, 如果希望默认的构造器在别的文件中使用,必须提供一个 public访问级别的
无参数构造器。
如果 结构体中的 存储型属性的访问级别是private,默认的逐一构造器的访问级别是private
协议
协议继承 不能通过继承,把原来的协议访问级别拉高
protocol asdfasd {
func adfa()
var hellor:String
let idnor:Int
}
internal protocol asdfasd {
private func adfa()
private var hellor:String
internal let idnor:Int
}
internal protocol fasdHeritProtocol:adfas {
}
类型别名
类型别名的访问级别 不可高于其他表示的类型的访问级别
private typealias helloClalss = String