Swift中weak与unowned的区别
在闭包里面为了解决循环引用问题,使用了 [unowned self]
。如果回调在self已经被释放后再调用,会导致crash掉。
解决:使用weak修饰。
weak与unowned的区别:
unowned设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil 。如果你尝试调用这个引用的方法或者访问成员属性的话,程序就会崩溃。而 weak 则友好一些,在引用的内容被释放后,标记为 weak 的成员将会自动地变成 nil (因此被标记为 @ weak 的变量一定需要是 Optional 值)。
map、flatMap、filter、reduce
map:转换,可以对数组中的元素格式进行转换
//将Int数组转换为String数组
//$0代表数组的元素
let array = [1, 2, 3, 4, 5 , 6, 7]
let result = array.map{
String($0)
}
flatMap与map不同之处:
(1)flatMap返回后的数组中不存在nil,同时它会把Optional解包
(2)flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组
(3)flatMap也能把两个不同的数组合并成一个数组,这个合并的数组元素个数是前面两个数组元素个数的乘积
let fruits = ["Apple", "Orange", "Puple"]
let counts = [2, 3, 5]
let array = counts.flatMap { count in
fruits.map ({ fruit in
return fruit + " \(count)"
})
}
array // ["Apple 2", "Orange 2", "Puple 2", "Apple 3", "Orange 3", "Puple 3", "Apple 5", "Orange 5", "Puple 5"]
filter:过滤,可以对数组中的元素按照某种规则进行过滤
//在array中过滤出偶数
let result2 = array.filter{
$0 % 2 == 0
}
reduce:计算 ,可以对数组中的元素进行计算
//计算数组array元素的和
//在这里$0和$1的意义不同,$0代表元素计算后的结果,$1代表元素
//10代表初始化值,在这里可以理解为 $0初始值 = 10
let result3 = array.reduce(10){
$0 + $1
}
逃逸闭包与非逃逸闭包
在Swift 3 后,传递闭包到函数中的时候,系统会默认为非逃逸闭包类型 (Nonescaping Closures)@noescape,有非逃逸闭包类型必然就有逃逸闭包(Escaping Closures),逃逸闭包在闭包前要添加@escaping关键字
非逃逸闭包的生命周期:1.把闭包作为参数传给函数;2.函数中调用闭包;3.退出函数,闭包生命周期结束
即非逃逸闭包的生命周期与函数相同
逃逸闭包的生命周期:1.闭包作为参数传递给函数;2.退出函数; 3.闭包被调用,闭包生命周期结束
即逃逸闭包的生命周期长于函数,函数退出的时候,逃逸闭包的引用仍被其他对象持有,不会在函数结束时释放
经常使用逃逸闭包的2个场景:
异步调用: 如果需要调度队列中异步调用闭包,比如网络请求成功的回调和失败的回调,这个队列会持有闭包的引用,至于什么时候调用闭包,或闭包什么时候运行结束都是不确定,上边的例子。
存储: 需要存储闭包作为属性,全局变量或其他类型做稍后使用,例子待补充。
关键字详解
关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符。关键字是对编译器具有特殊意义的预定义保留标识符。
常见的关键字有以下4种。
**与声明有关的关键字**
:class、deinit、enum、extension、func、import、init、let、protocol、static、struct、subscript、typealias和var。
**与语句有关的关键字**
:break、case、continue、default、do、else、fallthrough、if、in、for、return、switch、where和while。
**表达式和类型关键字**
:as、dynamicType、is、new、super、self、Self、Type、COLUMN、FILE、FUNCTION和LINE。
**在特定上下文中使用的关键字**
:associativity、didSet、get、infix、inout、left、mutating、none、nonmutating、operator、override、postfix、precedence、prefix、rightset、unowned、unowned(safe)、unowned(unsafe)、weak和willSet。
final
final关键字可以在class、func和var前修饰。表示 不可重写 可以将类或者类中的部分实现保护起来,从而避免子类破坏
Swift - final关键字的介绍,以及使用场景
static
static关键字声明静态变量或者函数,它保证在对应的作用域当中只有一份, 同时也不需要依赖实例化。注意:(用static关键字指定的方法是类方法,他是不能被子类重写的
)
mutating
mutating关键字指的是可变即可修改。用在structure和enumeration中,虽然结构体和枚举可以定义自己的方法,但是默认情况下,实例方法中是不可以修改值类型的属性。为了能够在实例方法中修改属性值,可以在方法定义前添加关键字mutating
struct rect {
var width = 0,height = 0
mutating func changeRect(x:Int, y:Int) {
self.width += x
self.height += y
}
}
enum Direction {
case Top, Left, Right, Bottom
mutating func lookDirection() {
switch self {
case .Top:
self = .Top
case .Left:
self = .Left
case .Right:
self = .Right
case .Bottom:
self = .Bottom
}
print("self === \(self)")
}
}
var re = rect(width: 5, height: 5)
re.changeRect(x: 32, y: 15)
print("re = \(re)")
/**
打印结果为:re = rect(width: 37, height: 20)
*/
var dir = Direction.Left
dir.lookDirection()
/**
打印结果为:self === Left
*/
required
required是用来修饰init方法的,说明该构造方法是必须实现的
class PerSon {
var name:String
required init(name : String) {
self.name = name
}
}
class Student: PerSon {
required init(name:String) {
super.init(name: name)
}
}
extension
在swift中,extension与Objective-C的category有点类似,但是extension比起category来说更加强大和灵活,它不仅可以扩展某种类型或结构体的方法,同时它还可以与protocol等结合使用,编写出更加灵活和强大的代码。它可以为特定的class, strut, enum或者protocol添加新的特性。当你没有权限对源代码进行改造的时候,此时可以通过extension来对类型进行扩展。extension有点类似于OC的类别 -- category,但稍微不同的是category有名字,而extension没有名字。在Swift 中的可以扩展以下几个:
(1)定义实例方法和类型方法
(2)添加计算型属性和计算静态属性
(3)定义下标
(4)提供新的构造器
(5)定义和使用新的嵌套类型
(6)使一个已有类型符合某个接口
// 添加计算属性
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
}
class Person {
var name:String
var age:Int = 0
init?(name:String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
extension Person {
//添加方法
func run() {
print("走了50公里")
}
}
let oneInch = 25.4.km
print("One inch is \(oneInch) meters")
/**
输出结果:One inch is 25400.0 meters
*/
let person = Person.init(name: "xiaom")
person?.run()
/**
输出结果:走了50公里
*/
convenient
swift中,使用convenience修饰的构造函数叫做便利构造函数 。便利构造函数通常用在对系统的类进行构造函数的扩充时使用。便利构造函数有如下几个特点:
(1)便利构造函数通常都是写在extension里面
(2)便利函数init前面需要加载convenience
(3)在便利构造函数中需要明确的调用self.init()
extension UIButton{
//swit中类方法是以class开头的方法,类似于oc中+开头的方法
class func createButton(imageName:String)->UIButton{
let btn=UIButton()
btn.setImage(UIImage(named:imageName), for: .normal)
btn.sizeToFit()
return btn
}
/*
convenience:便利,使用convenience修饰的构造函数叫做便利构造函数
便利构造函数通常用在对系统的类进行构造函数的扩充时使用。
*/
convenience init(imageName:String,bgImageName:String){
self.init()
if !imageName.isEmpty {
setImage(UIImage(named:imageName), for: .normal)
}
if !imageName.isEmpty {
setBackgroundImage(UIImage(named:bgImageName), for: .normal)
}
sizeToFit()
}
}
let btn = UIButton.init(imageName: "huanying", bgImageName: "")
btn.frame = CGRect.init(x: 10, y: 120, width: 100, height: 30)
btn.backgroundColor = UIColor.red
self.view.addSubview(btn)
deinit
在Swift中,deinit属于析构函数,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。和OC中的dealloc 一样的,通常在deinit和dealloc中需要执行的操作有:
(1)对象销毁
(2)KVO移除
(3)移除通知
(4)NSTimer销毁
fallthrough
swift语言特性switch语句的break可以忽略不写,满足条件时直接跳出循环.fallthrough的作用就是执行完当前case,继续执行下面的case.类似于其它语言中省去break里,会继续往后一个case跑,直到碰到break或default才完成的效果。
Private FilePrivate Public Open的作用和区别
https://blog.csdn.net/Mazy_ma/article/details/70135990
private 修饰符
只允许在当前类中调用,不包括 Extension
private 现在变为了真正的私有访问控制
用 private 修饰的方法不可以被代码域之外的地方访问
fileprivate 修饰符
fileprivate 其实就是过去的 private。
其修饰的属性或者方法只能在当前的 Swift 源文件里可以访问。
即在同一个文件中,所有的 fileprivate 方法属性都是可以访问到的。
class A {
fileprivate func test(){
print("this is fileprivate func!")
}
}
class B:A {
func show(){
test()
}
}
public 修饰符
修饰的属性或者方法可以在其他作用域被访问
但不能在重载 override 中被访问
也不能在继承方法中的 Extension 中被访问
open
open 其实就是过去的 public,过去 public 有两个作用:
- 修饰的属性或者方法可以在其他作用域被访问
-
修饰的属性或者方法可以在其他作用域被继承或重载 override
internal
在Swift中,public表示内部的访问权限。即有着internal访问权限的属性和方法说明在模块内部可以访问,超出模块内部就不可被访问了。在Swift中默认就是internal的访问权限。
从高到低排序如下:
open > public > interal > fileprivate > private
guard
guard 是一个新的条件声明,表示如果条件不满足时退出当前 block。任何被声明成 guard 的 optional 绑定在其他函数或 block 中都是可用的,并强制在 else 中用 return 来退出函数、continue 或 break 退出循环,或者用一个类似 fatalError() 的 @noreturn 函数来退出,以离开当前的上下文:
defer(推迟)
- defer的block,总是在当前方法执行后才会执行,一般会在block里面写释放资源代码。
postfix func ++(inout x: Int) -> Int {
defer { x += 1 }
return x
}
try? :告诉系统可能有错, 也可能没错, 如果发生错误, 那么返回nil, 如果没有发生错误, 会见数据包装成一个可选类型的值返回给我们
try! : 告诉系统一定没错, 如果发生错误, 程序会崩溃. 不推荐使用
inout
一般参数仅仅是在函数内可以改变的,当这个函数执行完后变量就会被销毁,不会有机会改变函数以外的变量,inout可以修改外部参数。
声明函数时,在参数前面用inout修饰,在函数内部实现改变外部参数
,注意,这里只能传入变量,不能传入常量和字面量,因为这些是不能变的一旦定义,当我们传入的时候,在变量名字前面用&符号修饰表示,传递给inout参数,表明这个变量在参数内部是可以被改变的
注意:inout修饰的参数是不能有默认值的,有范围的参数集合也不能被修饰,另外,一个参数一旦被inout修饰,就不能再被var和let修饰了
dynamic 的作用
由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic, 可以参考文章http://www.jianshu.com/p/ae26100b9edf
什么时候使用 @objc
@objc 用途是为了在 Objective-C 和 Swift 混编的时候, 能够正常调用 Swift 代码. 可以用于修饰类, 协议, 方法, 属性.
常用的地方是在定义 delegate 协议中, 会将协议中的部分方法声明为可选方法, 需要用到@objc
?? 的作用
可选值的默认值, 当可选值为nil 的时候, 会返回后面的值. 如
let someValue = optional1 ?? 0