本文是阅读Apple官方文档Using Swift with Cocoa and Objective-C (Swift 2.2)的总结,方便以后翻阅
类方法和便捷初始化方法
OC的类方法转到swift中为convenience initializers
可失败的初始化
OC中失败的初始化多返回 nil,可失败的初始化方法 可以用nullable
标记。OC中可失败和不可失败的初始化方法转到swift表示为init(...)
init?(...)
否则 为init!(...)
存取属性
OC中的@property
声明的属性转到swift中,规则如下:
- 有为空性属性的属性(
nonnull, nullable, and null_resettable
)转到swift对应于 optional 和 non-optional
类型
- OC的只读属性 在swift中表示为 计算属性 并只有一个getter(
{ get }
)
- OC的
weak
属性 在swift中用 weak
关键字表示 (weak var
)
- OC中的
assign, copy, strong, or unsafe_unretained
在swift中表示为一些 适当的存储
- OC中属性的原子性(
atomic and nonatomic
) 在swift中没有对应的属性声明的映射,但是从swift中调用OC中的属性时,其原子性的实现仍然有效
- OC中的属性
getter= and setter=
在swift中忽略
id的兼容性
swift中的AnyObject
对应OC中的id
,可以在AnyObject
类型的对象上 调用任意OC的方法和属性 并且不需要类型转换,包括用@objc
属性标记的OC兼容的属性和方法
Unrecognized Selectors and Optional Chaining
因为AnyObject
类型的对象的 值 到runtime时才回确定,所以很可能导致不安全的代码。跟OC一样 可能会抛出Unrecognized Selector
swift使用optionals
保证代码的安全,可以像使用protocol中的可选方法一样,使用optional chaining语法 在AnyObject
类型的对象上调用方法
note:在AnyObject
类型的对象上存取一个 属性 总是返回一个optional value。如果这个属性 正常情况下 返回optional的值,那么返回值会是双层包装的optional类型,如AnyObject?!
虽然swift不强制解包装 AnyObject
对象调用方法的返回值,但是为了安全编码,推荐使用解包装
向下转换 AnyObject
当AnyObject
类型的对象的底层数据类型已知或者可推断时,推荐向下转换到一个确定类型。因为AnyObject
可以是任意类型,向下转换到确定类型不保证一定成功。
条件类型转换操作符as?
返回一个optional value的目标类型。
若确定是某一种类型,可使用强制类型转换符as!
。注意 一旦强转失败 在runtime时会出错
Nullability and Optionals
OC中为初始化的指针为NULL(nil),在swift中 所有类型的值都是non-null的,并用optional
类型去封装值缺失,用nil表示
OC中的Nullability可以用(_Nullable _Nonnull nullable nonnull null_resettable
)标记,或者用NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END
宏包裹某个区域。如果OC代码没有这些标记,转swift时 不能区分到底是optional还是non-optional引用 所以只能标记为隐式解封装的optional(implicitly unwrapped optional)
_Nonnull
标记 转为non-optional
_Nullable
标记 转为optional
- 没有Nullability标记声明的 转为 implicitly unwrapped optional
轻量级泛型
OC中的Foundation框架的集合类的泛型才能转到swift中,其他类型的泛型不能转到swift 及没有泛型
extensions
swift的extensions相当于OC的category。extensions可以扩展已存在类 结构体 枚举类型 属性(属性扩展 必须为 计算属性),还可以扩展在OC中定义的这些类型。
extensions不能向类 结构体 枚举中添加存储属性,只能是 计算属性
extensions不需子类化 就可以使一个类遵守某个protocol,如果这个protocol是定义在swift中的,那么还可以使swift和OC中定义的结构体和枚举实现该protocol。
extensions还可以重写OC类型中 已存在的方法和属性
Closures
OC中的block
等价与swift中的closures
。混编时 block
会自动转为swift中的closures
并标记为@convention(block)
属性。swift中closures
长这个样子:
closures
跟block
兼容,可以将swift中的closures
传给OC中的block
,如果一个closures
和一个swift函数有相同的参数类型,神之可以把函数名传给OC中的block
。 closures
和block
最大的区别是 后者捕获到的变量是copy
, 而前者是mutable
,简言之 closures
的默认行为相当于 block
中的捕获到用__block
修饰的变量
避免循环引用
OC中循环引用出现的条件:self strong/copy block
,并且这个存在于堆上的block
内部出现了self
,使用的标准姿势如下(这可是apple的demo奥):
swift中处理closures
的循环引用 要讲self
指定为unowned
,姿势如下:
对象比较
swift中有两种比较操作符 ==
和===
: 前者比较对象内容是否相同,默认调用isEqual
方法; 后者比较对象是否指向同一个引用,检查指针是否指向同一地址。 在自定义子类中 要自己实现isEqual
方法,这涉及到对象等同性的判断,同OC
note:swift自动提供equality(==)和 identity(===)操作符的逻辑实现:!= 和 !==, 这些不要重写
hashing
这部分同OC,NSObject
的子类在等同性判断时 也要实现hash
属性
swift的类型兼容性
OC转swift的类中,属性 方法 下标 初始化方法等是兼容可用的,但是一些swift特有的feature是不支持的,如下:
- 泛型 generics
- 元组 tuples
- swift中的 非
Int
原始数据类型 的枚举
- swift中定义的结构体
- swift中的顶级函数
- swift中的全局变量
- swift中的类型别名 Typealiases
- swift风格的可变参数 variadics
- 嵌套类型 Nested types
- 柯里化函数
swift的API转OC与OC转swift相同:
- swift中的 optional 类型标记为
__nullable
- swift中的 non-optional 类型标记为
__nonnull
- swift的常量存储属性和计算属性转到OC中为read-only属性
- swift的变量存储属性转为OC中的read-write属性
- swift中的type method转为OC的类方法
- swift的初始化方法和实例方法转为OC的实例方法
- swift的抛出
errors
的方法转为OC的方法时 会在方法名后后缀一个NSError **
类型的参数。当改swift方法没有返回值时,相应的OC方法会有一个BOOL
类型的返回值
- 在OC代码中,不能子类化一个swift类
配置swift在OC中的接口
在需要控制swift API向OC暴露时,可以使用@objc(name)
属性去改变类 属性 方法 枚举类型 枚举成员暴露到OC中的名字
向swift函数提供一个OC的name时,如果用的selector语法,要在selector的参数后面加:
在swift中使用@objc(name)
属性时,转到OC时 没有命名空间。 当把一个可归档的OC类迁移到swift时,可以使用@objc(name)
属性指定与OC类相同的类名(因为已归档对象会存储归档的类名),这样就可以把原先已经归档的数据恢复到swift类中。
swift中@nonobjc
属性 会使swift的声明在OC中无法使用。这个可以用来解决 桥接方法 的环,或者 重新加载OC导入的类中的方法。如果OC的方法被swift的方法重写 并且该方法不能暴露给OC,比如指定一个参数为变量,那么这个方法必须标记为@nonobjc
Requiring Dynamic Dispatch
当在OC的runtime时 引入swift的API时,不能保证属性 方法 下标和初始化方法的动态派发。swift的编译器可能会绕过runtime 反虚拟化或者inline成员存取 来优化代码。 使用dynamic
可以要求成员的存取方法在OC的runtime动态派发。在使用KVO
或者OC runtime 的method_exchangeImplementations
函数时,需要使用该修饰符。这样swift编译器inline的方法实现或者反虚拟化的存取方法不会被使用。
note:用dynamic
修饰的 不能用 @nonobjc
属性
OC selectors
用OC的行为方式写swift类
继承OC类
subclassName: superclassName
如果要重写OC中的类 要用override
关键字
NSCoding
NSCoding协议必须实现init(coder:)
实现该协议的类的 子类中 如果有一个或多个自定义的初始化方法 或者 其他没有初始化值的属性 也必须要重写这个方法
从SB或者用NSUserDefaults or NSKeyedArchiver
加载的对象 必须要完全实现改方法
实现协议
OC中的协议转到swift中,会在父类后面用,
分隔 跟随协议名称
声明一个类型遵守单个协议 id<SomeProtocol>
-> var textFieldDelegate: UITextFieldDelegate
声明一个类型遵守多个协议 id<SomeProtocol, AnotherProtocol>
-> var tableViewController: protocol<UITableViewDataSource, UITableViewDelegate>
note:因为在swift中 类的命名空间和协议未定义,所以OC中的NSObject
协议映射为NSObjectProtocol
初始化方法 和 反初始化方法
#####
转载 留着以后看,哈哈
#对称加密:
#####DES
DES是1977年美国联邦信息处理标准中使用的一种对称密码技术,曾今被美国和其他国家政府银行使用。
不过现在已被暴力破解,我们除了用它解密以前的密文外,已不再使用DES了。不过这里我们可以用它来了解下什么是对称加密。
#####加密和解密
DES是一种把64比特明文加密成64比特的密文的对称密码算法,密钥长度56位,其中每隔7比特有个错误检查比特。结果DES密钥总长度为64比特。
#####分组密码
DES以64比特明文为一个单位进行加密,这64比特单位称为分组。so,以分组为单位处理密码的算法称为分组密码。DES属于分组密码。
DES每次只能加密64比特数据,如果明文较长,就需要对DES加密进行迭代,迭代的具体方式称为模式。后文会描述。
图DES加密与解密流程
#####三重DES
三重DES只是将DES重复3次,为了增加DES强度
#####AES
目前很安全
。。。。。
###分组密码模式
…..好多…..
#非对称加密
####公钥密码
在对称密码中,由于加密解密的密钥是相同的,因此密钥配送就成了问题。如过使用公钥密码,就解决了配送问题。
#####密钥配送问题:
解决密钥配送有多个方法,但都很难处理
1.双方通信时如果要加密,密钥不能在通信内容中。否则会被中间人窃听。
2.双方可以事先共享密钥,如果双方离得很近自然好说。但如果离得很远就不能在消息里传播密钥,因为可能会被窃听。邮寄存储卡也可能会被窃取。假如一个公司有1000人需要彼此加密通信,那密钥数可能会达到50万个,这个不现实。
3.如果有个密钥分配中心存储密钥,那1000人的数据库会有1000个密钥。但如果员工增加,密钥也要增加,数据库负荷会加大,如果数据库瘫痪,全公司的通信就会瘫痪。密钥分配中心也可能会遭到攻击.
4.Diffie-Hellman密钥交换。是个方案。我们在后续会讨论
#####公钥密码解决配送问题
两种密钥。一种是加密密钥,一种是解密密钥
这里有公钥和私钥,公钥和私钥既可以当做加密密钥,也可以做解密密钥。只是使用场景不同
你既可以用公钥加密,私钥解密。也可以用公钥解密,私钥加密。区别只是在于使用场景。
公钥和私钥是一一对应的,一对公钥和私钥统称为密钥对
我们来看一种公钥加密,私钥解密的情景。
Alice要发消息给Bob
1.Bob要接受消息,生成密钥对。私钥自己保管,公钥发给Alice
2.公钥被截获也没关系。因为公钥只负责加密
3.Alice用公钥对消息加密,发送给Bob。
4.即使密文中间被截获也没关系,公钥无法解密
5.Bob用自己私钥揭秘
如图所示
#####公钥密码的问题
1.公钥是否是正确合法的.假如中间人给你换了个公钥呢?
2.处理速度要比对称加密慢很多,大约只有百分之一
我们后面讨论这两个问题
####RSA
RSA加密
密文 = 明文 E mod N (mod是取模的意思)
E和N的组合就是公钥 简称 “公钥是(E,N)”
RSA解密
明文 = 密文 D mod N
D和N的组合就是私钥
####中间人攻击
这个逻辑很简单,中间人替换掉了接受者得公钥,向对方提供了自己的公钥。结果发送者用的中间人的公钥加密消息发送出去,中间人接受到消息并用自己私钥解密得到明文。再伪造一个假消息用接受者的公钥加密还给接受者。具体流程如图:
#混合密码技术
组成机制:
- 用对称密码加密消息
- 通过伪随机数生成器生成对称密码加密中使用的会话密钥
- 用公钥加密会话密钥
- 从混合密码系统外部赋予公钥密码时使用的密钥
#######混合密码系统加密解密过程
加密:
- 使用伪随机生成器生成会话密钥 ,会话密钥加密明文生成密文
- 用接受者的公钥加密会话密钥
- 两个密文组合后发送出去
解密:
- 收到消息先解密会话密钥,用接受者的私钥解密,得到会话密钥
- 用会话密钥解密加密过得密文,即可得到消息
#认证
#####单向散列函数
输入称为消息,输出称为散列值。
单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。
######单向散列函数的性质:
- 根据任意长度的消息计算出固定长度的散列值
- 能够快速计算出散列值
- 消息不同散列值也不同
- 两个不同消息产生同一个散列值的情况称为碰撞
- 要找到和该消息具有相同散列值的另外一条消息是非常困难的。这一性质称为弱抗碰撞性
- 要找到散列值相同的两条不同消息是非常困难的。称为强抗碰撞性
- 具备单向性
######关于术语
单项散列函数又称为消息摘要函数,哈希函数或者杂凑函数
######实际应用
- 检测软件是否篡改
- 基于口令的加密(PBE):原理是将口令和炎(伪随机数)混合后计算其散列值,然后将这个散列值用作加密密钥
- 消息认证码:检测并防止通信过程中得错误,篡改和伪装
- 数字签名
- 伪随机数生成器
- 一次性口令
###消息认证码
消息的认证是指:“消息来自正确的发送者”。通过使用消息认证码,我们就可以同时识别出篡改和伪装,既可以确认消息完整性,也可以进行认证。
消息认证码的输入包括任意消息的长度和一个接受者和发送者之间的共享密钥,输出是固定长度,这个数据称为MAC值。
消息认证码是一种与密钥相关联的单项散列函数。
如图:
使用步骤:如图
###数字签名
数字签名就是将公钥反过来用实现的。
公钥加密就是用公钥加密消息,用私钥解密密文。
而数字签名是用私钥对消息生成签名,传输数字签名的密文,最后用公钥解密验证签名。
如图所示:
解释一下:用私钥加密所得的密文,只能用公钥才能解密。这就是说,如果某个公钥成功解密了密文,那就证明这段密文是由与他配对的私钥进行加密所得的。
#####数字签名方法
###通过RSA实现数字签名
签名 = 消息的D次方 mod N
D和N就是签名者的私钥
有签名求得的消息 = 签名的E次方 mod N
E和N就是签名者的公钥
数字签名无法解决的问题
公钥必须属于真正的发送者。即使数字签名算法再强大,如果你得到的公钥是伪造的,那么数字签名也会完全失败。我们需要使用一种社会性的基础设施,即公钥基础设施。简称PKI。
见下文。
#证书
公钥证书和身份证,驾照很相似,里面有姓名,证件号,地址等个人信息,以及属于此人的公钥,由认证机构施加数字签名。只要看到公钥证书,我们就可以知道认证机构认定该公钥的确属于此人。公钥证书简称证书。
#####证书应用场景
如图:
#公钥基础设施(PKI)
公钥基础设施是为了能够更有效地运用公钥而制定的一系列规范和规格的总称。
#####PKI的组成要素
- 用户———使用PKI的人
- 认证机构————颁发证书的人
- 仓库————保存证书的数据库
######用户
分两种:1.一种是使用PKI注册自己的公钥的人。
2.另一种是使用已注册的公钥的人。
######认证机构(CA)
认证机构接受对证书进行管理的人。认证机构具体行为如下:
- 生成密钥对
- 在注册公钥时对本人进行身份认证
- 生成并颁发证书
- 作废证书
#####仓库
保管证书的数据库,也叫证书目录
PKI组成要素
#密钥,随机数与应用技术
####什么是密钥
- 密钥本身就是一个巨大的数字,数字大小不重要,重要的是密钥空间的大小,也就是说可能出现密钥的总数量。因为密钥空间越大,暴力破解就越困难。密钥空间大小有密钥长度决定。
- 密钥与明文是等价的,假如明文具有100万的价值,那么这段密钥也具有100万的价值;假如明文值1亿,密钥也值1亿。
- 不要使用自己开发的密码算法进行加密,而是使用一个经过全世界密码雪茄共同验证的密码算法。如果你使用了自己的密钥,可能会出现你的密钥被长时间破解了,你依然无法知晓。 信息的机密性不应该依赖密码算法本身,而是依赖于妥善保管的密钥。
####Diffie-Hellman 密钥交换
Diffie-Hellman 密钥交换算法,通信双方仅通过交换一些可以公开的信息就能够生产出共享密钥的
##基于口令的密码(PBE)
基于口令的密码就是一种根据口令生成的密钥并用该密钥进行加密的方法。其中加密和解密使用同一种密钥
PBE加密过程如图:
3个步骤:
1.生成KEK
2.生成会话密钥并加密
3.加密消息
PBE解密过程:
个人觉得是不是箭头反了?
#随机数
#####随机数的用途
其中生成密钥和生成密钥对是最重要的,即使密码强度再高,只要攻击者知道了密钥,就会立刻变得形同虚设。因此我们需要用随机数来生成密钥,使之无法被攻击者看穿。
#####随机数的性质
如图
#####伪随机数生成器
通过硬件生成的随机数列是根据传感器收集的热量,声音的变化等事实上是无法预测的。像这样的设备就称为随机数生成器。
而可以生成随机数的软件则称为伪随机数生成器。因为软件无法生成真随机数。
伪随机数生成器具有“内部状态”,并根据外部输入的“种子”来生成伪随机数列
#####伪随机数生成器的内部状态
伪随机数生成器的内部状态,是指伪随机数生成器岁管理的内存中的数值。
当有一条伪随机数的请求时,伪随机数生成器会根据内存中的数值进行技术,并将结果输出。随后改变自己的内部状态。因此,根据内部状态计算伪随机数的方法和改变内部状态的方法组合起来,就是伪随机数生成的算法。
#####伪随机数生成器的种子
伪随机数的种子是用来对伪随机数生成器的内部状态进行初始化。伪随机数生成器是公开的,但种子是需要自己保密的。由于种子不可以被攻击者知道,因此不可以使用容易被预测的值。
#PGP—密码技术的完美组合
用PGP加密
用PGP解密
用PGP生成数字签名
PGP验证数字签名
PGP生成数字签名并加密
PGP解密并验证数字签名
在做开发的时候,UI适配方面老代码都是使用frame
做UI布局,新的代码却是用的Autolayout
,我们主要是用的三方库masonry
写约束完成布局。在这个过程中。我一直有个错误的认识,Autolayout
不会改变frame
。网上看到很多blog也这么认为。这么认为多是由于设置完约束之后,打印frame
的值为CGRectZero
或者一个错误值造成的。但是在我调试一段代码时,情况却超出了我原来(错误)的认识。为什么打印的frame
完全正确?
答案是设置约束后frame
的更新并不是实时的,需要等到根据约束计算好view
的位置和尺寸之后才会刷新frame
。 Autolayout
的本质是通过一套约束规则去确定一个view
在superview
中的位置和尺寸。既是位置和尺寸那不就是frame
嘛。所以我通过文档和实验得出了以下几个结论:
Autolayout
是一套关于view
位置和尺寸的约束规则
Autolayout
改变可以改变view
的frame
,但是frame
的改变并不能改变Autolayout
的约束规则(当translatesAutoresizingMaskIntoConstraints = YES
时,会根据autoresizingMask
的相应设置更新相应的约束,但是这很可能会与既有的约束冲突,iOS7很有可能crash。设置translatesAutoresizingMaskIntoConstraints = NO
是推荐的做法,所以我们可以认为更改frame
不会改变约束),约束应该通过约束更新的方式改变。想要在Autolayout
改变后立即看到frame
的变化,请调用以下代码来立即刷新UI的布局
Autolayout
和frame
能否混用,答案是一定程度上可以,牢记上面一条两者之间的相互影响关系。在约束布局的UI视图中,混用frame
布局,一定要先调用上面的这段代码,这样就能得到superView
和相关view
准确的frame
。但是修改frame
不会修改约束使得混用的情况的变得复杂很容易出错,所以还是大众化的建议:最好不要混用。
- 在一些业务处理时,在约束布局后,需要获取
view
的宽高尺寸等信息,不用说,先调用上面的代码。这也可以说是一种混用的情况吧。
- 一些人认为在
viewDidLayoutSubviews
和 viewDidAppear
中布局已经确定,可以获取实际的frame
,诚然如此。这样也比每次调通上面的代码效率高。但是这只适用于进入页面后布局不在变化的情况,假如在当前页面一些操作触发了约束变化,那么这种做法就不适用了。上面这段代码虽然效率低,但是适用范围更大。
按照鄙人一贯风格,废话不多说,进入正题。本文是对iOS动画基础知识的总结,以便以后查阅,有不对的地方,敬请指正。
Core Animation
是iOS和OS X平台上负责图形渲染与动画的基础框架。具体为何物,相信看官已经有了一个感性的认识,具体Google之。iOS平台上的动画分为隐式动画和显式动画。Core Animation
基于一个假设:屏幕上的任何东西都可以(可能)做动画。动画并不需要你在Core Animation
中手动打开,相反需要明确地关闭,否则他会一直存在。
隐式动画
隐式动画的意思是说我们并没有指定任何动画的类型。我们仅仅改变了一个属性,然后Core Animation
来决定如何并且何时去做动画。 但当你改变一个属性,Core Animation
是如何判断动画类型和持续时间的呢?实际上动画执行的时间取决于当前事务(CATransaction)的设置,动画类型取决于图层行为。隐式动画的默认duration
为0.25s。简而言之,任何在一次run loop
循环中属性的改变都会被集中起来,然后做一次0.25s的动画。 我们直接改变CALayer
的可动画属性,会有隐式动画的效果,但是改变UIView
的对应属性就没有隐式动画的效果,因为UIView
将关联的图层的动画禁用了。想在UIView
上做动画,只能用显示动画 或者 用其他方式打开禁用。
关于隐式动画,就简单的讲这么多,我们的重点是在显式动画上。
显式动画
Core Animation
类及常用属性
Core Animation
的类图
各类常用属性
CAMediaTiming
:CALayer
和Core Animation
都实现了这个协议,它模拟了一个定时系统的层级,它的每个对象都描述了从父类对象到本地的时间值的映射。从父类时间线到本地转化的步骤见文档。
CAnimation
:核心动画基础类,为抽象类,不能直接使用,实现CAMediaTiming
协议
timingFunction
:调速功能属性,定义动画的步速。CAMediaTimingFunction
类型,系统预定义的步速类型分为以下几种:
- kCAMediaTimingFunctionLinear:线型步速,即匀速
- kCAMediaTimingFunctionEaseIn:先慢后快(慢进快出)
- kCAMediaTimingFunctionEaseOut:先快后慢(快进慢出)
- kCAMediaTimingFunctionEaseInEaseOut:先慢后快再慢
- kCAMediaTimingFunctionDefault:默认值,中间比较快
delegate
:设置动画委托,有两个委托方法:
* `removedOnCompletion`:是否自动在动画结束时将动画从渲染树上移除,默认是`YES` - `CAAnimationGroup`:动画组,将一些列动画组合到一起。
* `animations`:`CAAnimation`数组类型,成员为其他类型的动画 - `CAPropertyAnimation`:属性动画,继承于`CAnimation`
* `keyPath`:要做动画的的属性的`keyPath`,使用kvc匹配到`CALayer`的可动画属性
***注意:组动画的duration和组内的成员动画的duration不同时,若成员动画duration>组动画duration,则成员动画会在组动画的活动时间后截断不再执行后面的部分,反之,成员动画会在组动画的活动时间后继续执行。*** - `CABasicAnimation`:基础动画类,继承于`CAPropertyAnimation`,并增加了以下三个`id`类型的属性:
* fromValue:要设置的`keyPath`属性对应的动画开始之前属性的值
* toValue:要设置的`keyPath`属性对应的动画结束之后的值
* byValue::要设置的`keyPath`属性对应的动画执行过程中改变的值
三个属性的取值如下表,需要注意的是,三个属性使用时组合方式有很多种,但是不能同时使用三个属性,否则会有冲突。
![](../images/CoreAnimationSummary/CABasicAnimationValue.png) - `CAKeyframeAnimation`:关键帧动画
* `values`:对象数组,提供每一个关键帧的属性数据。在数组赋值的时候,如果要考虑好的平滑过渡效果,需要将数组中第一个对象和最后一个对象设置为动画开始之前和动画结束后模型图层的属性值。这是因为`CAKeyframeAnimation`并不能自动把当前值作为第一帧,这样动画开始和结束后会有突然跳帧突变的效果。
* `path`:关键帧动画的执行路径,优先级要高于`values`,当设置此属性时,`values`属性不再起作用。
* `timingFunctions`:`CAMediaTimingFunction`类型数组,指定帧与帧之间过渡的步速。 - `CATransition`:过渡动画,前面的动画类型都是对可动画属性起作用,对不可动画属性做动画,就需要是用`CATransition`。
* `type`:过渡动画的动画类型,系统提供了四种过渡动画:
- kCATransitionFade 渐变效果
- kCATransitionMoveIn 进入覆盖效果
- kCATransitionPush 推出效果
- kCATransitionReveal 揭露离开效果
* `subtype`:过渡动画的动画方向,系统提供四个方向:
- kCATransitionFromRight 从右侧进入
- kCATransitionFromLeft 从左侧进入
- kCATransitionFromTop 从顶部进入
- kCATransitionFromBottom 从底部进入
* `startProgress`:动画开始点,取值范围[0,1]
* `endProgress`:动画结束点,取值范围[0,1]
动画的三种实现方式
一:UIView
层的方法调用,长相大概是下面这样子
二:UIView
层的方法调用,[begin commit]
模式,长相大概是下面这样子
三:CALayer
层的方法调用,使用Core Animation
中的子类,长相大概是下面这样子
需要注意的是 在使用frame
,Autolayout(指apple原生约束方式)
,Masonry
这三种常见方式布局的时候,实现位移、缩放等动画的方式也略有不同。使用约束布局的view做动画相对简单,只需要改变目标view的属性 关联的view会自动有动画效果,而使用frame布局时,需要将所有关联view的相应属性都做改变。
还有就是为了平滑过渡,无论使用那种动画方式都要设置好模型图层即动画开始和结束之后的属性值,否则会有跳帧突然回到初始状态的现象。
三种动画实现方式对frame
,Autolayout(指apple原生约束方式)
,Masonry
的适用
NOTE!
在使用委托方法时,先VC中把动画保存为一个属性,然后在委托方法中比较判断,这不起作用,因为委托方法中传入的animation
参数是原始值的一个deep copy
。 在委托方法中判断animation
的正确姿势是kvc & Dictionary
, CAAnimation
遵守kvc
协议,它的设计像一个NSDictionary
,所以我们可以用-setValue:forKey:
和-valueForKey:
方法设置一个标识tag
,根据这个tag去判断就好了,还可以做很多其他的工作奥,比如传递animaiton
所属的VC,使用很灵活。
扩展延伸阅读
Masonry基础使用
CATransform3D的基本属性
开发中遇到了一些不常见的关键字,原来只是一知半解,所以做了一些功课,总结了以下。
@encode()
在使用NSNumber
时,很可能会遇到这个关键字。在用masonry
时,也发现了这个关键字的使用场景。我们可以把int
、BOOL
等封装成NSNumber
对象,但是翻过来,我们怎么知道NSNumber
内封装的到底是什么原型的数据呢。就会用到@encode()
。
Objective-C 的数据类型,甚至自定义类型、函数或方法的元类型,都可以使用ASCII
编码。@encode(aType)
可以返回该类型的C
字符串(char *)
的表示。使用举例如下:
@class
这个关键字我用的很多,总而言之一句话,.h
文件内,能用@class
就别导入头文件。
@dynamic
这个关键字是相对于@synthesize
的,用于动态合成property
。编译器不会合成accessor
,runtime
时动态解析。
@defs
这个关键字把OC对象转化成对应的struct
结构体。这个struct
与原OC
类具有相同的内存布局。OC
类底层也是C struct
和一些方法的封装。涉及非常底层的操作或优化的时候才会用到。示例代码如下:
struct { @defs( NSObject) }
@autoreleasepool
用于ARC
下代替NSAutoreleasePool
的关键字。一般用于降低app的内存峰值,包裹敏感代码。
@compatibility_alis
用于给一个类设置一个别名。这样就不用重构以前的类文件就可以用新的名字来替代原有名字。示例代码如下
@compatibility_alias AliasClassName ExistingClassName
附:OC保留的关键字列表
扩展阅读
关于Objective-C warning的笔记
那些被遗漏的Objective-C保留字
The Complete List of Objective-C 2.0 @ Compiler Directives