第八课:
1、协议
另一种安全处理id类型的方式如:id <MyProtocol> obj
a.声明
//协议一般放于.h文件中或者在类的.h文件中 @protocol Foo <Xyzzy, NSObject>//<>中的内容表示还需实现自哪些协议,所有协议的根协议一般都是NSObject - (void)someMethod;//默认为必须实现的方法 @optional//可选方法声明 - (void)methodWithArgument:(BOOL)argument; @required @property (readonly) int readonlyProperty; //只有getter在协议中 @property NSString *readwriteProperty; //getter与setter都在协议中 - (int)methodThatReturnsSomething; @end
b.在类中实现协议
#import “Foo.h” @interface MyClass : NSObject <Foo> //(do not have to declare Foo’s methods again here, it’s implicit that you implement it) @end //或者私有实现 @interface MyClass() <Foo> @end @implementation MyClass //@required methods here! @end
c.用途
①委托
②数据源
//UI与controller盲通信的方式 @property (nonatomic, weak) id <UISomeObjectDelegate> delegate; @property (nonatomic, weak) id <UISomeObjectDataSource> dataSource;
③动画
2、Block(来源于API文档)
实际上为一段代码块,类似于C语言中的函数指针
a.声明
int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num * multiplier; }; //int 为block返回值 //^表示为此为代码块 //myBlock为此代码块名 //int 为参数类型 //等号右边为block实现
block可以使用和他的同一范围内声明的变量,使用block与使用C函数类似
int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num * multiplier; }; printf("%d", myBlock(3)); // prints "21"
b.直接使用block
block可以省略block声明直接使用
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" }; //直接使用block作为参数 qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) { char *left = *(char **)l; char *right = *(char **)r; return strncmp(left, right, 1); }); // myCharacters is now { "Charles Condomine", "George", "TomJohn" }
c.Cocoa中使用block
NSArray *stringsArray = @[ @"string 1", @"String 21", @"string 12", @"String 11", @"String 02" ]; static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch; NSLocale *currentLocale = [NSLocale currentLocale]; //比较器为代码块 NSComparator finderSortBlock = ^(id string1, id string2) { NSRange string1Range = NSMakeRange(0, [string1 length]); return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale]; }; NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock]; NSLog(@"finderSortArray: %@", finderSortArray); /* Output: finderSortArray: ( "string 1", "String 02", "String 11", "string 12", "String 21" ) */
d.__block变量
首先看简单的例子
//直接使用变量 int x = 123; void (^printXAndY)(int) = ^(int y) { printf("%d %d/n", x, y); }; printXAndY(456); // prints: 123 456 //不可以直接更改变量,此处变量对block来说为只读 int x = 123; void (^printXAndY)(int) = ^(int y) { x = x + y; // error printf("%d %d/n", x, y); };
解决方法,引入__block变量
__block int x = 123; // x lives in block storage void (^printXAndY)(int) = ^(int y) { x = x + y; printf("%d %d/n", x, y); }; printXAndY(456); // prints: 579 456 // x is now 579
e.各种类型的变量在block中的使用
对于普通局部变量,在block声明时保存其值,之后普通局部变量的改变对block不可见
//注意block的调用时机 extern NSInteger CounterGlobal;//block对全局变量有读写权限 static NSInteger CounterStatic;//静态变量 { NSInteger localCounter = 42;//普通本地变量 __block char localCharacter;//__block本地变量 void (^aBlock)(void) = ^(void) { ++CounterGlobal; ++CounterStatic; CounterGlobal = localCounter; // localCounter fixed at block creation localCharacter = 'a'; // sets localCharacter in enclosing scope }; ++localCounter; // unseen by the block,对block不可见,block的值认为42 localCharacter = 'b'; aBlock(); // execute the block // localCharacter now 'a' }
f.对象在block中的使用
dispatch_async(queue, ^{ /* block中访问实例变量,instanceVariable为block所在类的实例变量,此时直接访问了实例变量,因此需要对包含它的对象(self)保留 */ doSomethingWithObject(_instanceVariable); }); id localVariable = _instanceVariable; dispatch_async(queue, ^{ /* 在本地创建了指向实例变量的引用,因此需要保留localVariable而不是self */ doSomethingWithObject(localVariable); });
g.使用typedef声明block
typedef float (^MyBlockType)(float, float); MyBlockType myFirstBlock = // ... ; MyBlockType mySecondBlock = // ... ;
h.Memory Cycles
//block中引用self,所以有强指针指向self,而block又在self中定义,所以self又有强指针指向block [self.myBlocks addObject:^ { [self doSomething]; }];
解决方法
__weak MyClass *weakSelf = self; //重新声明为弱引用 [self.myBlocks addObject:^ { [weakSelf doSomething]; }];
i.用途
枚举,动画,排序,通知(Notification),Error handlers,Completion handlers (错误与完成事件的处理,可以理解为回调函数), 多线程 等
3、动画(Animation)
a.动画的种类
Animating views :视图动画,包括移动、缩放、淡入淡出、旋转等
Animation of View Controller transitions:视图控制器动画,视图的切换等
Core Animation:核心动画框架
本节课只涉及视图动画
b.为视图添加动画的三种方法
①通过设置视图属性
frame
transform (translation, rotation and scale)
alpha (opacity)
值会立即改变,但动画效果会延时
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;//适用于常规动画设置 //example [UIView animateWithDuration:3.0 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ myView.alpha = 0.0; } completion:^(BOOL fin) { if (fin) [myView removeFromSuperview]; }];//视图在3秒内从父视图淡出,完成动画后并移除自己 + (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;//适用于转场动画设置,比如卡牌的翻转 + (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;//适用于切换视图动画
//UIViewAnimationOptions //常规动画属性设置(可以同时选择多个进行设置) UIViewAnimationOptionLayoutSubviews //父视图变化时自动更新子视图约束@see:http://segmentfault.com/q/1010000002872390 UIViewAnimationOptionAllowUserInteraction //动画时响应用户事件,如 touch等 UIViewAnimationOptionBeginFromCurrentState //从当前状态开始动画,比如此时有动画正在改变属性 UIViewAnimationOptionRepeat //无限制重复动画 UIViewAnimationOptionAutoreverse //执行动画回路(动画运行到结束点后仍然以动画方式回到初始点),前提是设置动画无限重复 UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套动画时间设置 UIViewAnimationOptionOverrideInheritedCurve //忽略嵌套动画速度设置 UIViewAnimationOptionAllowAnimatedContent //动画过程中重绘视图(注意仅仅适用于转场动画) UIViewAnimationOptionShowHideTransitionViews //视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画) UIViewAnimationOptionOverrideInheritedOptions //不继承父动画设置或动画类型 //动画速度控制(可从其中选择一个设置) UIViewAnimationOptionCurveEaseInOut //动画先缓慢,然后逐渐加速 UIViewAnimationOptionCurveEaseIn //动画逐渐变慢 UIViewAnimationOptionCurveEaseOut //动画逐渐加速 UIViewAnimationOptionCurveLinear //动画匀速执行,默认值 //转场类型(仅适用于转场动画设置,可以从中选择一个进行设置,基本动画、关键帧动画不需要设置) UIViewAnimationOptionTransitionNone //没有转场动画效果 UIViewAnimationOptionTransitionFlipFromLeft //从左侧翻转效果 UIViewAnimationOptionTransitionFlipFromRight //从右侧翻转效果 UIViewAnimationOptionTransitionCurlUp //向后翻页的动画过渡效果 UIViewAnimationOptionTransitionCurlDown //向前翻页的动画过渡效果 UIViewAnimationOptionTransitionCrossDissolve //旧视图溶解消失显示下一个新视图的效果 UIViewAnimationOptionTransitionFlipFromTop //从上方翻转效果 UIViewAnimationOptionTransitionFlipFromBottom //从底部翻转效果
②Dynamic Animator :动力动画
实现步骤:a.创建一个UIDynamicAnimator
b.向UIDynamicAnimator添加UIDynamicBehaviors(gravity, collisions, etc.)
c.向UIDynamicAnimator添加UIDynamicItems(usually UIViews)
d.动画自动运行
//Create a UIDynamicAnimator UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:aView]; //Create and add UIDynamicBehaviors UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; [animator addBehavior:gravity]; UICollisionBehavior *collider = [[UICollisionBehavior alloc] init]; [animator addBehavior:collider]; //Add UIDynamicItems to a UIDynamicBehavior id <UIDynamicItem> item1 = ...; id <UIDynamicItem> item2 = ...; [gravity addItem:item1]; [collider addItem:item1]; [gravity addItem:item2];
//UIDynamicItem 协议 @protocol UIDynamicItem @property (readonly) CGRect bounds; @property (readwrite) CGPoint center; @property (readwrite) CGAffineTransform transform; @end //一般UIView即可作为Item,天生实现了UIDynamic协议 //以上属性一般有动画运行时的animator来改变,若需要主动改变,需要调用 - (void)updateItemUsingCurrentState:(id <UIDynamicItem>)item;
UIDynamicBehaviors
//UIGravityBehavior @property CGFloat angle;//重力方向,默认向下 @property CGFloat magnitude; // 1.0 is 1000 points/s/s //UICollisionBehavior 碰撞 @property UICollisionBehaviorMode collisionMode; // Items,Boundaries,Everything (default) - (void)addBoundaryWithIdentifier:(NSString *)identifier forPath:(UIBezierPath *)path; //用UIBezierPath自定义碰撞边界 @property BOOL translatesReferenceBoundsIntoBoundary;//参考视图(动力动画的顶级视图)作为碰撞边界 //UIAttachmentBehavior 吸附行为 - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)anchor;//以点作为吸附 - (instancetype)initWithItem:(id <UIDynamicItem>)i1 attachedToItem:(id <UIDynamicItem>)i2;//以动力项作为吸附,两个动力项的吸附 - (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(CGPoint)offset ... //偏移中心的吸附 @property (readwrite) CGFloat length; // 吸附的长度 @property (readwrite) CGPoint anchorPoint; // 吸附点 @property (readwrite, nonatomic) CGFloat damping; // 锚点移动时的阻尼 @property (readwrite, nonatomic) CGFloat frequency; // 锚点移动时的频率 //UISnapBehavior 捕捉行为 - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point; @property CGFloat damping;.//移动到锚点时振动的阻尼 //UIPushBehavior 推动行为 @property UIPushBehaviorMode mode; // Continuous or Instantaneous @property CGVector pushDirection; @property CGFloat magnitude/angle; // magnitude 1.0 moves a 100x100 view at 100 pts/s/s //UIDynamicItemBehavior 动力项行为,应用于所有Items @property (readwrite, nonatomic) CGFloat elasticity; // 弹力,[0.1] @property (readwrite, nonatomic) CGFloat friction; //摩擦力,0表示无摩擦力 @property (readwrite, nonatomic) CGFloat density; // 密度,默认为1 @property (readwrite, nonatomic) CGFloat resistance; //线性阻力系数0--CGFLOAT_MAX @property (readwrite, nonatomic) CGFloat angularResistance; //角度阻力系数0--CGFLOAT_MAX @property (readwrite, nonatomic) BOOL allowsRotation; //是否允许旋转 - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item;//获取Item速度 - (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item;//获取Item角速度
创建UIDynamicBehavior子类实现自定义行为
- (void)addChildBehavior:(UIDynamicBehavior *)behavior;//将其他行为添加到自定义行为中 @property UIDynamicAnimator *dynamicAnimator;//获取当前行为所在的Animator - (void)willMoveToAnimator:(UIDynamicAnimator *)animator;//行为加入到方法或者移除时(此时参数为nil)会调用 @property (copy) void (^action)(void);//每当行为发生时总会执行此block,注意调用比较频繁的效率问题
4、demo
Dropit: https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/515b76c7ed6e74a7e30108efe6d4c833f33a6e0c
课程视频地址:网易公开课: http://open.163.com/movie/2014/1/D/L/M9H7S9F1H_M9H80D0DL.html
或者iTunes U搜索standford课程