FaceBook POP源碼解析二

FaceBook POP源碼解析一git

FaceBook POP源碼解析三github

FaceBook POP源碼解析四bash

1、前言

本文主要專一於源碼分析,具體pop的相關使用,可參考下文連接架構

2、POP源碼架構

pop源碼主要分爲Animations、Engine、Uility和WebCore四部分,每一部分承擔不一樣的職責。工具

pop

  • Animations:包含了pop中全部的動畫類型
  • Engine:負責pop中的動畫處理
  • Uitity:經常使用到的一些工具類
  • WebCore:包括矩陣處理以及貝塞爾曲線等

3、POP動畫類型

pop中可以使用的動畫包括POPBasicAnimation、POPSpringAnimation、POPDecayAnimation和POPCustomAnimation四種,具體類之間的關係以下:源碼分析

animation

1.POPAnimation

該類相似於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方法。

2.POPAnimation分類

該分類主要提供了外部對動畫增刪查的接口,但實際上真正執行這些操做的是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
複製代碼

4、總結

本小節主要介紹了pop的大體架構以及動畫的基類POPAnimation的相關內容。該小節比較值得關注的一點就是pop將OC對象和struct對象之間的相互轉化。

相關文章
相關標籤/搜索