内容简介:本文是对不断更新中~mutating关键字是用来在方法中修改struct或enum变量的,若不声明会报错。
本文是对 喵神 编写的 《Swift必备Tips(第四版)》 的读书笔记,内容是我不太熟悉或觉得有用的Swift使用技巧。
不断更新中~
将protocol的方法声明为mutating
mutating关键字是用来在方法中修改struct或enum变量的,若不声明会报错。
static和class 关键字
异同点
相同点:static和class都是表示“类型范围作用域”这一概念的。
不同点:class是专门用在class类型的上下文中的,可以用来 修饰类方法和类属性。
class中现在是不能出现在class的存储属性的。
class MyClass{ class varbar:Bar? }
会得到一个编译错误,class variables not yet supported,改成static就可以通过编译了。
结论
任何时候使用static都是没问题的。
多类型和容器使用Any/AnyObject的技巧
Swift中常用的原生容器类型有 Array/Dictionay/Set ,他们都是范型的,也就是说放在一个集合中的类型要一致。
但是Any可以让我们在容器中放各种类型的元素,但也不可避免的带来了 部分信息损失 ,从容器中取出后还需要进行一次类型转换。
// Any 类型可以隐式转换 let mixed: [Any] = [1, "two", 3] // 转换为 [NSObject] let objectArray = [1 as NSObject, "two" as NSObject, 3 as NSObject] //建议的使用方式 let mixed: [CustomStringConvertible] = [1, "two", 3] for obj in mixed { print(obj.description) }
改善方法一
作者认为,把这些不同类型的元素放到一个容器中,肯定是由于他们有 共性 ,也就是这些元素服从某个共同的协议,这样虽有一定损失,但相对于Any或AnyObject还是改善了不少。
改善方法二
另一种做法是用enum可以带有值的特点,将类型信息 封装到enum中 。
enum IntOrString{ case IntValue(Int) case StringValue(String) } let mixed = [IntOrString.IntValue(1), IntOrString.StringValue("two"), IntOrString.IntValue(3)] for value in mixed { switch value { case let .IntValue(i): print(i * 2) case let .StringValue(s): print(s.capitalized) } }
AnyClass
除了上面提到的Any和AnyObject,还有一个表示 任意 这个概念的东西 AnyClass 。在Swift中的定义方式:
typealias AnyClass = AnyObject.Type
得到的是一个元类型(Meta),存储的是一个类的类型本身。除了可以用元类型来调用类方法或类变量,还可以用在 传递类型的时候,不需要不断地改动代码了。
let usingVCTypes: [AnyClass] = [MusicViewController.self, AlbumViewController.self] func setupViewControllers(_vcTypes: [AnyClass]) { for vcType in vcTypes { if vcType is UIViewController.Type { let vc = (vcType as! UIViewController.Type).init() print(vc) } } } setupViewControllers(usingVCTypes)
在编框架时,搭好框架后,用DSL的方式进行配置,就可以在不触及Swift编码的情况下,完成一系列复杂操作了。另外,Cocoa API中,也经常需要一个AnyClass的输入,如:self.tableView.registerClass(
UITableViewCell.self, forCellReuseIdentifier: “myCell”)
Self
首字母大写的Self,通常用在协议内,指代实现协议的类型 和子类 。实现代理方法有点技巧。
protocol Copyable{ func copy() -> Self } class MyClass:Copyable{ var num = 1 func copy() -> Self { let result = type(of: self).init() result.num = num return result } required init() { } }
直接使用MyClass()进行初始化是错误的,无法编译,因为该方法要求返回的是一个 抽象的 、表示当前类型的Self,而不是真实类型MyClass。type(of:)在js中也有,保证了方法与当前类型上下文无关,无论是MyClass还是它的子类,都可以正确地返回合适的类型,满足Self的要求。
注意需要有required关键字修饰init方法, 保证当前类和子类都能响应init方法 ,否则type(of: self).init()可能会出错。另一个解决方法是申明class为 final ,保证不会有其他子类来继承这个类型,本质上也是保证type(of: self).init()不会出错。
动态类型和多方法
Swift默认是不采用动态派发的,方法调用在编译时决定。如果想绕开这个限制,需要手动对输入类型做判断与转换。如果没有判断,即使printThem的函数第一个参数传入Dog(),也是派发的Pet的printPet()方法。
func printThem(_pet: Pet,_cat: Cat) { if let aCat = pet as? Cat { printPet(aCat) } else if let aDog = pet as? Dog { printPet(aDog) } printPet(cat) }
final 关键字
上面提到了final,作者对final关键字的态度是: 虽然final能告诉编译器这段代码不会被更改,但是提升的性能非常有限,建议先优化算法和图像相关的内容。
final真正适用的几个场景:
- 类方法或功能以及确实完备了,比如很难会重写计算字符串MD5或AES加密解密的 工具 类。
- 子类继承和修改是一件危险的事情,比如在某个公司管理的系统中我们对员工按照一定规则进行编号,这样通过编号我们能迅速找到任一员工。而假如我们在子类中重写了这个编号方法,很可能就导致基类中的依赖员工编号的方法失效。
- 为了父类中某些代码一定会被执行。比如有时候父类中有一些关键代码是在被继承重写后必须执行的 (比如状态配置,认证等等),否则将导致运行时候的错误。
lazy 关键字
在构建和生成新的对象时,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂,耗时不可忽略;另外,有些情况下,我们不会立即使用到一个对象的所有属性,默认初始化会将全部变量初始化,包括特定环境下的存储属性,这是一种浪费,懒加载就是为此而生。
lazy除了可以修饰属性,也有其他用法:
func lazy<S : SequenceType>(s: S) -> LazySequence<S> func lazy<S : CollectionType where S.Index : RandomAccessIndexType>(s: S) -> LazyRandomAccessCollection<S> func lazy<S : CollectionType where S.Index : BidirectionalIndexType>(s: S) -> LazyBidirectionalCollection<S> func lazy<S : CollectionType where S.Index : ForwardIndexType>(s: S) -> LazyForwardCollection<S> let data = 1...3 let result = data.lazy.map { (i: Int) -> Int in print("正在处理\(i)") return i * 2 } print("准备访问结果") for i in result { print("操作后结果为\(i)") } print("操作完毕")
用来配合像map和filter这类接受闭包并进行运行的方法一起,让整个行为变成延时的。有lazy和无lazy的输出是完全不同的。 对于那些不需要完全运行,可能提前退出的情况,使用lazy是进行性能优化的一种有效手段。
以上所述就是小编给大家介绍的《《Swift必备Tips》读书笔记》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【Java高阶必备】如何优化Spring Cloud微服务注册中心架构?【石杉的架构笔记】
- 高阶Java开发必备:分布式系统的唯一id生成算法你了解吗?【石杉的架构笔记】
- Java进阶必备:优雅的告诉面试官消息中间件该如何实现高可用架构?【石杉的架构笔记】
- 前端开发必备工具
- go语言开发必备
- RabbitMQ必备核心知识
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。