FaceBook POP源碼解析三github
本文主要專一於源碼分析,具體pop的相關使用,可參考下文連接架構
pop源碼主要分爲Animations、Engine、Uility和WebCore四部分,每一部分承擔不一樣的職責。工具
pop中可以使用的動畫包括POPBasicAnimation、POPSpringAnimation、POPDecayAnimation和POPCustomAnimation四種,具體類之間的關係以下:源碼分析
該類相似於CAAnimation,是動畫的抽象基類,提供一些共用的屬性和方法。post
@interface POPAnimation : NSObject
//屬性對應的名稱,用於區分動畫對象
@property (copy, nonatomic) NSString *name;
//開啓動畫的時間
@property (assign, nonatomic) CFTimeInterval beginTime;
@property (weak, nonatomic) id delegate;
//用於記錄動畫過程
@property (readonly, nonatomic) POPAnimationTracer *tracer;
//動畫開始時被調用
@property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim);
//當動畫屬性值達到或超過設置的值時被調用
@property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim);
//動畫結束時被調用
@property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished);
//動畫每執行完一幀後被調用
@property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim);
//動畫執行完後,是否移除動畫,默認爲NO,若設置爲YES,動畫執行完後,會恢復原狀
@property (assign, nonatomic) BOOL removedOnCompletion;
//獲取動畫執行的狀態
@property (assign, nonatomic, getter = isPaused) BOOL paused;
//是否執行來回動畫
@property (assign, nonatomic) BOOL autoreverses;
//動畫重複次數
@property (assign, nonatomic) NSInteger repeatCount;
//是否一直重複動畫
@property (assign, nonatomic) BOOL repeatForever;
@end
//獲取動畫的執行狀態
@protocol POPAnimationDelegate <NSObject>
@optional
- (void)pop_animationDidStart:(POPAnimation *)anim;
- (void)pop_animationDidReachToValue:(POPAnimation *)anim;
- (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished;
- (void)pop_animationDidApply:(POPAnimation *)anim;
@end
複製代碼
a. POPAnimation爲抽象類,不能被實例化動畫
- (id)init
{
[NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."];
return nil;
}
複製代碼
b. POPAnimation的初始化:在初始化方法中,建立了一個POPAnimationState對象,並將本身做爲參數傳遞過去。ui
- (void)_initState
{
_state = new POPAnimationState(self);
}
複製代碼
POPAnimationState爲一個struct聲明,裏面包含與POPAnimation對應的屬性atom
struct _POPAnimationState
{
id __unsafe_unretained self;
POPAnimationType type;
NSString *name;
NSUInteger ID;
CFTimeInterval beginTime;
CFTimeInterval startTime;
CFTimeInterval lastTime;
id __weak delegate;
POPAnimationDidStartBlock animationDidStartBlock;
POPAnimationDidReachToValueBlock animationDidReachToValueBlock;
POPAnimationCompletionBlock completionBlock;
POPAnimationDidApplyBlock animationDidApplyBlock;
NSMutableDictionary *dict;
POPAnimationTracer *tracer;
CGFloat progress;
NSInteger repeatCount;
...
}
複製代碼
c. POPAnimation的setter和getter方法
- (BOOL)isPaused
{
return _state->paused;
}
- (void)setPaused:(BOOL)paused
{
_state->setPaused(paused ? true : false);
}
- (NSInteger)repeatCount
{
if (_state->autoreverses) {
return _state->repeatCount / 2;
} else {
return _state->repeatCount;
}
}
- (void)setRepeatCount:(NSInteger)repeatCount
{
if (repeatCount > 0) {
if (repeatCount > NSIntegerMax / 2) {
repeatCount = NSIntegerMax / 2;
}
if (_state->autoreverses) {
_state->repeatCount = (repeatCount * 2);
} else {
_state->repeatCount = repeatCount;
}
}
}
複製代碼
咱們能夠看到setter其實就是將對應的屬性賦值給_state,getter也是從_state中獲取再返回。也就是說其實POPAnimation能夠看做是一箇中介者,是OC暴露的接口,實際上操做這些屬性仍是經過POPAnimationState結構體。
d.使用宏來簡化OC對象與結構體之間屬性的轉換
#define FB_PROPERTY_GET(stype, property, ctype) \ - (ctype)property { \ return ((stype *)_state)->property; \ }
#define FB_PROPERTY_SET(stype, property, mutator, ctype, ...) \ - (void)mutator (ctype)value { \ if (value == ((stype *)_state)->property) \ return; \ ((stype *)_state)->property = value; \ __VA_ARGS__ \ }
#define DEFINE_RW_PROPERTY_OBJ(stype, flag, mutator, ctype, ...) \ FB_PROPERTY_GET (stype, flag, ctype) \ FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__)
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidStartBlock, setAnimationDidStartBlock:, POPAnimationDidStartBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidReachToValueBlock, setAnimationDidReachToValueBlock:, POPAnimationDidReachToValueBlock);
複製代碼
對於須要特殊處理的setter和getter方法,則須要重寫,而常規的setter和getter方法,則經過宏來簡化這一過程。
e.重寫valueForUndefinedKey方法
- (id)valueForUndefinedKey:(NSString *)key
{
return _state->dict[key];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if (!value) {
[_state->dict removeObjectForKey:key];
} else {
if (!_state->dict)
_state->dict = [[NSMutableDictionary alloc] init];
_state->dict[key] = value;
}
}
複製代碼
在KVC調用valueForKey方法時,若key不存在,則會拋出NSUndefinedkeyException異常,爲了不該異常,重寫了valueForUndefinedKey方法。
該分類主要提供了外部對動畫增刪查的接口,但實際上真正執行這些操做的是POPAnimator對象。
@interface NSObject (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key;
- (void)pop_removeAllAnimations;
- (void)pop_removeAnimationForKey:(NSString *)key;
- (NSArray *)pop_animationKeys;
- (id)pop_animationForKey:(NSString *)key;
@end
@implementation NSObject (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
{
[[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
}
- (void)pop_removeAllAnimations
{
[[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
}
- (void)pop_removeAnimationForKey:(NSString *)key
{
[[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
}
- (NSArray *)pop_animationKeys
{
return [[POPAnimator sharedAnimator] animationKeysForObject:self];
}
- (id)pop_animationForKey:(NSString *)key
{
return [[POPAnimator sharedAnimator] animationForObject:self key:key];
}
@end
複製代碼
本小節主要介紹了pop的大體架構以及動畫的基類POPAnimation的相關內容。該小節比較值得關注的一點就是pop將OC對象和struct對象之間的相互轉化。