FaceBook POP源码解析二

1,573 阅读4分钟

FaceBook POP源码解析一

FaceBook POP源码解析三

FaceBook POP源码解析四

一、前言

本文主要专注于源码分析,具体pop的相关使用,可参考下文链接

二、POP源码架构

pop源码主要分为Animations、Engine、Uility和WebCore四部分,每一部分承担不同的职责。

pop

  • Animations:包含了pop中所有的动画类型
  • Engine:负责pop中的动画处理
  • Uitity:常用到的一些工具类
  • WebCore:包括矩阵处理以及贝塞尔曲线等

三、POP动画类型

pop中可使用的动画包括POPBasicAnimation、POPSpringAnimation、POPDecayAnimation和POPCustomAnimation四种,具体类之间的关系如下:

animation

1.POPAnimation

该类类似于CAAnimation,是动画的抽象基类,提供一些共用的属性和方法。

@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对象,并将自己作为参数传递过去。

- (void)_initState
{
  _state = new POPAnimationState(self);
}

POPAnimationState为一个struct声明,里面包含与POPAnimation对应的属性

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

四、总结

本小节主要介绍了pop的大致架构以及动画的基类POPAnimation的相关内容。该小节比较值得关注的一点就是pop将OC对象和struct对象之间的相互转化。