美高梅官方网站3045-mgm6608美高梅app下载
swift一些关键字的理解

swift一些关键字的理解

作者:mgm美高梅 官方网址    来源:未知    发布时间:2020-02-02 13:12    浏览量:

摘要:Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化。我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的。其实就是安全。在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。所以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

Swift 是类型安全的语言,有超级严格的初始化方法

1.typealias

class ClassA { let numA: Int init(num: Int) { numA = num } } class ClassB: ClassA { let numB: Int override init(num: Int) { numB = num + 1 super.init(num: num) } } 

不加修饰的 init 方法都需要在方法中保证所有非 Optional 的实例变量被初始化,而在子类中也强制(显式货隐式的)调用了 super 的 designated 指定的初始化。

//声明一个闭包类型 AddBlock

在上面的示例代码中,注意在init里我们可以对let的实例常量进行赋值,这是初始化方法的重要特点。在Swift中let声明的值是不变量,无法被写入赋值,这对于构建线程安全的API十分有用。而因为Swift的init只可能被调用一次,因此在init中我们可以为不变量进行赋值,而不会引起任何线程安全的问题。与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是Swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience初始化方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。

美高梅官方网站3045,// 这里非 Optional 的变量在外面有自己的默认值的时候,初始化方法可以不用给他们初始化

typealias AddBlock = (Int,Int)->(Int);

class ClassA { let numA: Int init(num: Int) { numA = num } convenience init(bigNum: Bool) { self.init(num: bigNum ? 10000 : 1) } } class ClassB: ClassA { let numB: Int override init(num: Int) { numB = num + 1 super.init(num: num) } } 

// 不加修饰的初始化方法 init 默认是 designated 指定的

class ViewController: UIViewController {

只要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就也可以使用父类的convenience初始化方法了。比如在上面的代码中,我们在ClassB里实现了init(num: Int)的重写。这样,即使在ClassB中没有bigNum版本的convenience init(bigNum: Bool),我们仍然还是可以用这个方法来完成子类初始化:

与 designated 初始化方法对应的是在 init 前面加上 convenience 关键字的初始化方法

override func viewDidLoad() {
super.viewDidLoad()
let add:AddBlock = {
(a,b) in
return a + b;
}

let anObj = ClassB(bigNum: true) // anObj.numA = 10000, anObj.numB = 10001 

是 swift 初始化方法的 ‘二等公民’, 只作为补充和提供使用上的方便

let result = add(1100, 200);
print("result=(result)");
} }

因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:初始化路径必须保证对象完全初始化,这可以通过调用本类型的designated初始化方法来得到保证;子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。一个现成的例子就是上面的init(bigNum: Bool):如果我们希望这个初始化方法对于子类一定可用,那么应当将init(num: Int)声明为必须,这样我们在子类中调用init(bigNum: Bool)时就始终能够找到一条完全初始化的路径了:

注意: 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化方法来完成设置。

2.escaping

class ClassA { let numA: Int required init(num: Int) { numA = num } convenience init(bigNum: Bool) { self.init(num: bigNum ? 10000 : 1) } } class ClassB: ClassA { let numB: Int required init(num: Int) { numB = num + 1 super.init(num: num) } } 

另外,convenience 初始化方法是不能被子类重写或者从子类中以 super 的方式被调用的

逃逸闭包一般用于异步函数的回调,比如网络请求成功的回调和失败的回调。语法:在函数的闭包行参前加关键字“@escaping” ((Any?)->(Void))?,也可以表示网络请求成功的回调,不过后面需带“?”,这代表闭包可选类,这并不是闭包类型的,两者对比如下:

另外需要说明的是,其实不仅仅是对designated初始化方法,对于convenience的初始化方法,我们也可以加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会非常有帮助。作者:王巍,iOS和Unity3D开发者。

class ClassA {

可选闭包

let numA:Int

func requestData(urlString:String,succeed: ((Any?)->(Void))?,failure:((Any?)->(Void))?){}

//如果这里加上了required关键字,表明子类必须也要加上required,但是去掉

逃逸闭包

override init(num:Int) {

func requestData(urlString:String,succeed: @escaping (Any?)->(Void),failure:@escaping (Any?)->(Void)){}

numA= num

注意

}

如果是在闭包内部调用控制器,那么必须显示的写self。防止闭包带来的循环引用的问题

convenience init(bigNumber:Bool){

如何解决闭包的循环引用, 同样有三种方式:

self.init(num: bigNumber ?10000:1)

使用weak修饰变量, 打破强引用, 因为使用weak修饰的变量有一次变成nil的机会

}

使用[weak self] 修饰闭包原理跟__weak类似, 这样在闭包中使用self, 就是弱引用

}

使用[unowned self ] 修饰闭包, 跟__unsafe_unretained类似, 不安全

下一篇:没有了
友情链接: 网站地图
Copyright © 2015-2019 http://www.zen-40.com. mgm美高梅有限公司 版权所有