《Swift必备Tips》读书笔记

栏目: Swift · 发布时间: 6年前

内容简介:本文是对不断更新中~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》读书笔记》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Probabilistic Method Second Edition

The Probabilistic Method Second Edition

Noga Alon、Joel H. Spencer / Wiley-Blackwell / 2000 / $121.95

The leading reference on probabilistic methods in combinatorics-now expanded and updated When it was first published in 1991, The Probabilistic Method became instantly the standard reference on one......一起来看看 《The Probabilistic Method Second Edition》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试