CS193P-2013 Lecture 8 协议、block、动画

协议

id obj

只是编译器中的语法,与 NSString * 等标识没有区别

编译时仍然是 id 类型,只是给编译器类型检查上的方便

  • 声明

    @protocol Foo 
    //如果实现 Foo, 必须实现 Xyzzy 和 NSObject 协议中的方法(类似于父协议)
    - (void)someMethod;
    - (void)methodWithArgument: (BOOL)argument;
    
    @optional
    //optional 标记下方的方法为可选,否则必须实现
    @property (readonly) int readonlyProperty;
    
    @required
    //这样下面两个方法/属性仍然必须实现
    @property NSString *readwriteProperty;
    - (int)methodThatReturnsSomething;
    @end
    
  • NSObject 协议

    里面的方法和 NSObject 类中的方法几乎完全一致。有时候为了让非 NSObject 类实现一些如内省的方法(很少用到)

  • @protocol 的位置

    头文件(可以是需要实现该协议的类的头文件,也可以是独立的)

  • 遵循协议:

    #import "Foo.h"
    @interface MyClass : NSObject 
    //实现所有 Foo 的 require 方法
    @end
    
  • 特性

    • 可以作为参数
    • 不像 NSString * 可以知道某个类的所有方法,也不像 id 一样什么都不知道,类似于一个折中的静态类型
    • 编译上不会对代码产生任何区别,只是方便编译器的代码提示等
  • 用途

    • 委托、数据源

Block

Block 是一段代码快,可以嵌入其他代码中

可以作为参数传递,也可以放在 NSArray 里

在其他语言中常被称为闭包

  • 示例

    [aDictionary enumerateKeyAndObjectsUsingBlock: ^(id key, id value, BOOL *stop) {
      //^returnType(arg1, arg2...) {//代码} 是 block 的基本形态
          //如果返回值可以被推断,可以不用显式写出
          //如果没有参数,可以连括号也省略
          NSLog(@"value for key %@ is %@", key, value);
          if ([@"ENOUGH" isEqualToString: key]) {
              *stop = YES;
          }
    }]
    //这段代码会对 aDictionary 中的全部键值对循环执行这个 block
    
  • 值捕获

    block 可以捕获在 block 之前被声明的变量,但该变量是只读的(在执行 block 时被保存在栈中)

    如果要修改这个变量,在变量声明之前加上 __block(将这个变量移到堆中)

  • 可存储性

    block 可以像对象一样被存放到 NSArray、NSDictionary 中

    @property (nonatomic, strong) NSMutableArray *myBlocks;
    [self.myBlocks addObject: ^ {
        [self doSomething];
    }]
    

  • 循环引用

    每次在 block 中向一个对象发送信息时,都会创建一个指向该变量的强指针(保存到 block 超出范围时)。

    如果在 block 中对 self 发送信息,则 self 保存了对 block 的强指针,block 保存了对 self 的强指针,就会造成循环引用导致两者都无法从堆中被释放。

    解决方法:

    __weak MyClass *weakSelf = self;  //使用一个弱指针的引用
    [self.myBlocks addObject: ^ {
          [weakSelf doSomething];
    }]
    
  • 用途
    • 枚举
    • 动画
    • 排序
    • 通知
    • completion handler

动画

  • 任意时刻都可以对视图的三个属性做动画操作

    • frame
    • transform(移动距离、旋转和缩放比例)
    • alpha(透明度)
  • 方法

    //注意这是一个 UIView 的类方法
    + (void)animateWithDuration: (NSTimeInterval)duration //持续时间
                        delay: (NSTimeInterval)delay      //延迟时间
                      options: (UIViewAnimationOptions)options    //选项
                   animations: (void (^)(void))animations //修改上述三个属性
                   completion: (void (^)(BOOL finished))compeltion;   //处理
    
    //示例:视图的淡出消失
    [UIView animateWithDuration: 3.0
                        delay: 0.0
                      options: UIViewAnimationOptionBeginFromCurrentState
                      //这个选项表示如果是在其他动画的执行过程中打断其进程,从打断的状态继续
                      //比如前一个动画的 alpha 从0.7变为0,变化到0.2时被打断,从0.2继续
                   animations: ^{myView.alpha = 0.0}  //修改会立刻生效
                   completion: ^(BOOL fin) { 
                          if (fin) [myView removeFromSuperview];
                          //如果动画没有正常结束(比如被另一个动画打断,这里的 fin 就是 false)
                     }
    ];
    

    对视图自身属性的修改会立即完成,但是动画会持续 duration 时间

  • 有时候会想要让整个视图一起被修改(比如翻转),或者要动画化非上述三个属性的修改操作

    + (void)transitionWithView : (UIView *)view
                    duration : (NSTimeInterval)duration
                     options : (UIViewAnimationOptions)options
                  animations : (void (^)(void))animations //修改属性
                  completion : (void (^)(BOOL finished))completion;
    
    /*
    options:
    UIViewAnimationOptionsTransitionFlipFrom{Lect, Right, Top, Bottom}
    UIViewAnimationOptionsTransitionCrossDissolve
    UIViewAnimationOptionsTransitionCurl{Up, Down}
    */
    
  • 如果需要改变视图的层级

    使用 transitionFromView 方法(类方法)

- dynamic animation 动力动画

定义一些物理效果,应用于要添加动画效果的视图,然后会被立刻执行

//创建一个 UIDynamicAnimator 动力动画者
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:aView];
//aView 必须是视图的顶级视图(Top)

//创建并添加 UIDynamicBehaviors(重力、碰撞等)到动力动画者中
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init];
[animator addBehavior:gravity];
UICollisionBehavior *collider = [[UICollisionBehavior alloc] init];
[animator addBehavior:collider];

//创建并添加 UIDynamicItems (通常是 UIView) 到动力行为中
id  item1 = ...;
id  item2 = ...;
[gravity addItem:item1];
[collider addItem:item1];
[gravity addItem:item2];

@protocol UIDynamicItem
@property (readonly) CGRect bounds;
@property (readwrite) CGPoint center;
@property (readwrite) CGAffineTransform transform;
@end
  
//如果 animator 在执行的时候需要修改 center 或 transform,需要调用 UIDynamicAnimator 的下述方法
- (void)updateItemUsingCurrentState: (id 
  • UIGravityBehavior - 重力行为

    • @property CGFloat angle
    • @property CGFloat magnitude (1.0表示 1000p/s/s 加速度)
  • UICollisionBehavior - 碰撞行为

    • @property UICollisionBehaviorMode collisionMode(Items, Boundaries, 缺省为 Everything)

      决定 Item 是互相碰撞时还是碰到边界时被弹开

    • @property BOOL translatesReferenceBoundsIntoBoundary;

    将参考视图的边界添加到弹性边界,碰到会被弹开

  • UIAttachmentBehavior - 吸附行为

  • UISnapBehavior - 速甩行为

  • UIPushBehavior - 推动行为

  • UIDynamicItemBehavior

    • 控制 item 的内在行为(摩擦力、密度等)
  • block 属性(所有的 Behavior 都有)

    一个无返回值无参数的闭包,当某个 behavior 被执行的时候,这个 block 就会被调用

你可能感兴趣的:(CS193P-2013 Lecture 8 协议、block、动画)