在Swift结构体中实现写时复制 | LiJun's Blog 

作者:JerryXia | 发表于 , 阅读 (0)
结构体(Struct)在Swift中占有重要地位,在Swift标准库中,大约有90%的公开类型都是结构体,包括我们常用的Array、String、Dictionary。结构体相比类,一个最重要的特性就是它是值类型,而类似引用类型。值类型是通过复制值来赋值的,而不是引用同一个内存地址,这样就不存在数据共享的问题,能防止意外的数据改变,并且它是线程安全的。
举一个很简单的例子,在objc中,数组是类,是引用类型,在Swift中,数组是结构体,是值类型。因此下面的代码中:
123456let array1 = NSMutableArray(array: ["lihua", "liming"])let array2 = array1array1.addObject("xiaowang")array2array1和array2最后都变成了["lihua", "liming", "xiaowang"],也就是array1的改变会导致array2也发生改变,因为它们两个都是引用类型,并且都引用了同一个内存地址。
而在Swift中,就不存在这样的问题:
123456var array3 = [...阅读全文

 《Advanced Swift》笔记:Swift字符串长度 | LiJun's Blog 

作者:JerryXia | 发表于 , 阅读 (0)
12345var str = "Pokémon"var nsstr = str as NSStringstr.characters.count  // 7nsstr.length // 8如上,同样一个字符串,在String和NSString下,它的长度却不一样。因为Unicode编码是一种可变长格式,Unicode字符串是由编码点(code point)组成,而编码点又是由编码单元(code unit)组成。在不同的编码标准下,同一个字符串,可能会有不同的编码方式。Swift中的String内部实现尽量符合“标准等价”的编码规范,使我们更准确的处理字符长度。
在OC的NSString中,我们常用length方法来获取字符串的长度,而在Swift的String中,没有了length方法,我们通常是使用characters.count来获取字符长度,如下:
12345var str = "Hello, playground"var nsstr = str as NSStringstr.characters.count // 17nsstr.length  // 17以上两种方法...阅读全文

 SICP-1.1程序设计的基本元素 | LiJun's Blog 

作者:JerryXia | 发表于 , 阅读 (0)
每一种强有力的语言都为此提供三种机制:
基本的表达形式,用于表示语言所关心的最简单的个体。组合的方式,通过它们可以从较简单的东西出发构造出复合的元素。抽象的方法,通过它们可以为复合对象命名,并将它们当作单元去操作。在程序设计中,我们需要处理两类要素:过程和数据。而这两者并不是严格分离的,数据是一种我们希望去操作的东西,而过程是有关操作这些数据的规则的描述。这样,任何强有力的程序设计语言都必须能表述基本的数据和基本的过程,还需要提供对过程和数据进行组合和抽象的过程。1.1.1 表达式Scheme中的基本表达式就是数:456、3、8…,解释器则会输出你键入的数的值:456、3、8…。
组合式:用表示过程的表达形式,将表示数的表达式组合起来,形成复合表达式。构成方式就是用一对括号括起一些表达式,形成一个表,表里最左边的元素是运算符,其它元素为运算对象。比如:
123(+ 137 349)(* 3 5 8)(- 4 9 8 76)这种将运算符放在所有运算对象左边的形式称为前缀表示。这种形式的一大好处就是适用于带有任意个实参的过程,表里右边的运算对象可以是任意个。前缀表示的另一个有点就是可...阅读全文

 Swift 协议的性能 | LiJun's Blog 

作者:JerryXia | 发表于 , 阅读 (0)
当我们通过协议类型来创建一个变量时,这个变量会被包装到一个叫做存在容器的盒子里,这个存在容器除了变量本身的数据外,还会存储一些其它的数据,因此它占用的内存会变大,相应的也会损失些性能。
一个协议类型,因为需要同时支持类、结构体、枚举,同时还要支持动态派发,因此协议内部需要维持这些类型、方法的相关数据。一个普通的协议的内部构造大致如下图:
协议内部会有一个存储值的缓冲区,一些元数据,还有若干个目击表。这些信息都需要占用一定的内存,因此协议类型所占用的内存要比具体的类、结构体、枚举等类型更大。比如下面这段代码,有一个Animal协议,一个Person结构体遵循协议,各有两个方法接受一个遵循Animal的变量作为参数,并返回这个参数的大小。其中第一个方法将协议当作泛型约束,第二个方法将协议当作独立类型来使用,其结果是第一个方法接受参数的大小为0,而第二个方法接受的参数大小达到了40。原因就是通过协议接受一个参数是,会将这个参数进行包装,添加上图中的信息,导致内存变大。
123456789101112131415protocol Animal {}struct Person: Anima...阅读全文

 Swift3+iOS8 下 UITableView 的神奇 bug | LiJun's Blog 

作者:JerryXia | 发表于 , 阅读 (0)
近期在我厂的实际项目中发现,在iOS 8系统中,Tableview cell 的排版出现了错乱,特别是在执行reloadRows:方法后,cell不仅会出现一个动画,最后高度还会不对,详情看动图:
后来经过层层排查,基本可以确定是系统的一个bug,在Swift3 + iOS 8的情况下才会出现。
排除可能的错误高度计算有误?出现这个问题后,从表面上看起来,似乎是高度计算有问题,但转念一想,我们用了高度缓存机制,高度只需要计算一次,只要第一次计算正确,后面再刷新不应该会出错呀。为了验证是不是高度有问题,采取了一个很简单的办法,直接将高度定死,设了一个固定值,发现没有这个动画和排版错误。因此初步得出结论是高度计算出现了问题。
于是接下来就是找到高度计算的问题。从bug表现来看,主要是cell的高度一开始基本是正常的(其实一开始也并不完全正常),主要是执行了reloadRows:方法后出问题,因此首先猜测是不是高度缓存出错了,缓存的key出问题了,还是中途哪里删除了缓存,然后再计算的时候就出错了。
然后通过打断点,一个个cell记录下key和高度,再和reloadRows:方法执行后...阅读全文