VSCode Snippets 使用手册
前言
当我们为了减少模板代码,我们第一个很可能想到使用Code Snippets
,很多IDE和文件编辑器已经给我们提供了一个预装的代码片段,当预装的代码片段不能瞒着我们的需求,我们可能会自己定制一些自己的专有代码代码片段,下面就为大家介绍如何在VSCode定制自己的代码片段以及一些小技巧。
在开发中,涉及价格金额处理,后台会返回Number类型的数据,打印或者经过Json转Model后的NSString可能出现精度丢失的问题,如果涉及到金额的加减乘除运算问题将暴露得更为明显。这里就iOS数据精度处理做一个总结。
1 | NSArray *numbers = @[ |
在这里我们发现将NSNumber转换成NSSting的过程中可能会出现精度丢失。
1 | //出现BUG的条件必须是两位数,且带两位小数,类型还必须是float |
在这里我们发现将Json解析成Model的过程中可能会出现精度丢失。
因为浮点数在计算机中是采用IEEE规定的标准浮点格式,即二进制科学表示法。
在这种表示法中,一个数 S = M * 2 ^ N
。
其中N表示阶码,M表示位数(有效数字位)。
例如一个float类型的浮点,在32bit位上,占4个字节,字节表示为
【31】N:【30 ~ 23】 M:【22~0】
指数N决定它的范围,因为M总是一个以1开头的小数,以float来说即是:-2 ^ 128 ~ 2 ^ 128,即float能表示的数的大小的范围。
而它的精度是由位数(也就是有效的数据位)来决定的, 2 ^ 23 = 8388608,总共7位,表示最多能用7位有效数字,最多能表示到.8388708即小数点后7位,由于不能完全表示全部的7位数,所以它的精度范围是6位~7位。
同理可得double的精度是2 ^ 52 = 4503599627370496, 共16位,所以精度为15 ~ 16位。
不同机器字节序的规定
公式: S = M * 2 ^ N
二进制在内存中是以补码形式存储,负数要对其二进制绝对值按位取反再加一,正数的补码与原码形式相同
也就是说float和doublel类型数据在计算机中存储可能是不精确的。
当我们需要转换成浮点类型是数据时,最好用double,因为double的精度更高,出现丢精度的概率相对是较小的。
在iOS中提供一个专用的类来处理浮点数据相关的运算:NSDecimalNumber
使用NSDecimalNumber
来进行浮点数处理。
我们给NSString添加一个分类来处理浮点运算问题
1 | ///.h |
1 | NSArray *numbers = @[ |
问题得以解决。☕️
参考资料:
排序是应用常见需求之一,如何正确优雅的实现一个排序,NSSortDescriptor
或许是一个非常好的选择。
NSSortDescriptor
由3个参数组成:
localizedStandardCompare:
选择器,它将根据语言规则进行排序(例如大小写,变音符号等等的顺序)NSSortDescriptor
主要针对各种集合排序,NSArray
,NSMutableArray
,NSSet
,NSOrderedSet
,NSMutableOrderedSet
如果集合是可变的,则对集合本身排序例如
NSMutableOrderedSet
的sortUsingDescriptors:
NSMutableArray
的sortUsingDescriptors:
如果集合是可变的,则返回一个排好序的新集合例如
NSArray
的sortedArrayUsingDescriptors:
NSSet
的sortedArrayUsingDescriptors:
NSOrderedSet
的sortedArrayUsingDescriptors:
注意排序描述是一个数组,也就是排序可以支持按照多个描述综合排序。如果存在多个规则先满足前面的规则再满足后面的规则。例如两个元素按照第一天规则顺序一致,那么如果还存在第二天规则,它们将按照第二条规则继续排序,如果前面的规则已经区分出顺序后面的规则将失效。
为了更好的描述,假如我们有一个Person
对象,它有**NSString * **类型的姓和名属性,以及一个NSNumber
类型的年龄属性。
1 | @interface Person : NSObject |
给定以下数据集:
index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
firstName | Alice | Bod | Charlie | Quentin | |
lastName | Smith | Jones | Smith | Alberts | |
age | 24 | 27 | 33 | 31 | 19 |
使用不同的NSSortDescriptor
的不同组合来将它们排序:
1 | NSArray *firstNames = @[@"Alice", @"Bod", @"Charlie", @"Quentin", @""]; |
NSNumber
对象来排序localizedStandardCompare:
选择器参考链接
Swift中枚举和结构体也上升到对象的位置,但是却不具备完整的对象特征,比如说他们不能继承。
在OC中枚举本质其实是整数类型,只是给他们取了一些意义直观的名称而已,而Swift完全摆脱以前的思想的束缚编的更自由,拥有了以下特征。
Character
,String
,Float
,Double
等,这些叫做原始值case
条件匹配可以定义参数,可以使用where
来过滤rawValue
可以拿到枚举的原始值如果提供了原始值,就可以在case声明成员时提供默认值,这样跟OC的枚举在结构上一些类似
1 | enum WeekDays : Int { |
1.声明一个枚举值
1 | let monday = WeekDays.Monday |
2.获取原始值
1 | let rawVlaue = WeekDays.Tuesday.rawValue |
3.通过原始值构造某个枚举变量
1 | let wednesday = WeekDays.init(rawValue: 2) |
和C的联合体有点类似
1.声明
1 | enum Figure { |
2.使用
1 | func printFigure(figure: Figure) { |
1 | typedef NS_OPTIONS(NSUInteger, NSVolumeEnumerationOptions) { |
1 | struct NSVolumeEnumerationOptions : OptionSetType { |
1 | UIView.animateWithDuration(0.3, |
Swift中加强了结构体的能力,可以定义和使用属性,方法,下标,构造器等,但是不能被继承,没有强制类型抓换,使用析构器和引用计数等能力
通常使用结构体来充当数据模型,常量可以使用静态关键词static
标示
weak
unowned
[unowned 捕获对象]或者
[weak 捕获对象]
使用实例
1 | class Person { |
如果我们可以确定在整个过程中 self 不会被释放的话,我们可以将上面的 weak 改为 unowned,这样就不再需要 strongSelf 的判断。但是如果在过程中 self 被释放了而 printName 这个闭包没有被释放的话 (比如 生成 Person 后,某个外部变量持有了 printName,随后这个 Persone 对象被释放了,但是 printName 已然存在并可能被调用),使用 unowned 将造成崩溃。在这里我们需要根据实际的需求来决定是使用 weak 还是 unowned。
NSString和String的关系:在Swift中,使用字符串可以使用Foundatio中的NSString和Swift中的String。
Swift在底层能够将String与NSString无缝地桥接起来,String可以调用NSString的全部API。
NSArray和Array的关系:Swift能在底层将他们自动桥接起来,一个NSArray对象桥接后的结果是[AnyObject]。
NSDictionary和Dictionary的关系: 底层自动桥接,一个NSDictionary对象桥接后的结果是[Object: AnyObject]。
类的转换使用 as
数据类型加括号 Int()
OC使用 (新的类型)原来的变量
is
关键词
相当于OC的isKindofClass:
NSAssert
assert()
创建一个动画,添加到不同的图层上,可以实现复用,通过调节beginTime
可以调节动画开始执行的时间。
例如,我们创建一个水平位移动画,添加到不同的图层对象上,并且让他们轮流执行。
1 | let flyRight = CABasicAnimation(keyPath: "position.x") |
动画的beginTime
属性可以设置将要执行的动画的绝对开始时间,通过CACurrentMediaTime()
函数获取当前时间再加上你想要延迟执行的时间的,单位秒。
动画代理可以监听动画的进行状态,在动画开始和结束的时候回通知代理.
也就是会调用以下两个函数:
1 | func animationDidStart(anim: CAAnimation) |
CAAnimation
和它的子类遵循KVO,也就意味着你可以把它们当成字典一样使用来添加新的接口在运行时。
例如你可以使用这种机制来给某个动画指定一个名字,以便你能够把它和其它动画区分开。
1 | flyRight.setValue("somename", forKey: "name") |
Property | Default Value |
---|---|
damping | 10.0 |
mass | 1.0 |
stiffness | 100.0 |
initialVelocity | 0.0 |
参数说明:
damping
- 应用给系统的阻尼mass
- 在系统中重物的质量stiffness
- 附加在重物上的弹簧的硬度initialVelocity
- 附加在重物上的初始速度使用实例:
1 | let jump = CASpringAnimation(keyPath: "position.y") |
备注:
此动画的duration
参数可以通过前面几个参数自动计算得出
jump.duration = jump.settlingDuration
对CAGradientLayer
的locations
属性做动画轻松的实现iPhone自带的滑动解锁效果
a.创建一个渐变图层
1 | let gradientLayer: CAGradientLayer = { |
b.创建一个文本样式字典
1 | let textAttributes : [String: AnyObject] = { |
c.当设置文本时绘制内容,添加@IBInspectable
方便看实时效果
1 | @IBInspectable var text: String! { |
d.重新布局gradientLayer
1 | override func layoutSubviews() { |
e.添加到window时向渐变层添加动画
1 | override func didMoveToWindow() { |