美文网首页
CS193P-2013 Lecture 8 协议、block、动

CS193P-2013 Lecture 8 协议、block、动

作者: _Patrik_ | 来源:发表于2016-05-09 21:04 被阅读32次

    协议

    id <Proctocol> obj

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

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

    • 声明

      @protocol Foo <Xyzzy, NSObject>
      //如果实现 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>
      //实现所有 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 <UIDynamicItem> item1 = ...;
    id <UIDynamicItem> 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 <UIDynamicItem) item;
    
    • 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、动

          本文链接:https://www.haomeiwen.com/subject/zpverttx.html