dissmiss后变短 ios_ios dissmiss viewwillappear - CSDN
  • 本文旨在总结iOS知识网络,知识点,该知识网络罗列出常见UIKit、Foundation的对象特点和一些使用经验,可以看成是一本书;文本编辑采用树的形式,对知识点进行罗列,并标注一些使用经验(★)希望对初学者有用或给...

            本文旨在总结iOS知识网络,知识点,该知识网络罗列出常见UIKit、Foundation的对象特点和一些使用经验,可以看成是一本书;文本编辑采用树的形式,对知识点进行罗列,并标注一些使用经验(希望对初学者有用或给一些解决疑难杂症者提供思路;某些知识点会深入探讨;通过总结希望站在一个较高平台的角度全观Objective-C。知识树中有些是原创文章,有些则是转载网络上iOS大神的文章。由于篇幅的限制笔者会简洁地介绍各个知识点,读者可通过链接了解详情。当然一个人的知识面是相当有限的,在给各位读者提供知识参考的同时,欢迎大家对本文提意见。

                                 /->UIViewController
                                 |        ViewController在iOS只是一个非常重要的概念翻译,其在一个App中所扮演的角色:
                                 |            (1) View Management:管理View     (2) Data Marshalling:管理数据
                                 |            (3) User Interactions:响应用户交互 (4) Resource Management:管理资源
                                 |            (5) Adaptivity:适配不同的屏幕尺寸空间的变化
                                 |         生命周期一片枫叶点击 另外一篇点击
                                 |        + (void)initialize +(void)load 的调用时机,区别点击
                                 |        ViewDidLoad调用时机:当view被首次使用的时候,某些情况可提升性能
                                 |        横竖屏的坑点击。APP整体是竖屏,单个controller可以是横屏的
                                 |         两种交互方式:push和present
                                 |            左右滑动 - (void)pushViewController:(UIViewController *) animated:(BOOL)
                                 |            模态,从下往上弹出 - (void)presentViewController:(UIViewController *) animated: (BOOL) completion:
                                 |            Can't add self as subview 这个crash是由于快速push两个UIViewController导致的【点击】
                                 |         一次dissmiss多个 present controller
                                    |                UIViewController *rootVC = self.presentingViewController;
                                    |                while (rootVC.presentingViewController) 
                                    |                    rootVC = rootVC.presentingViewController;
                                    |                [rootVC dismissViewControllerAnimated:YES completion:nil];
                                    |        ★pop到rootcontroller    [UINavigationController popToRootViewControllerAnimated:]
                                 |        还有一种:直接把Controller的view添加到另一个Controller上。
                                 |-> UIView
                                 |        
    frame 和bound 的区别点击
                                 |            frame 是相对父试图坐标的值; bound是本身坐标系统的值                            
                                 |        
    layoutSubviews点击 需要将[super layoutSubviews];放到最后,不然iOS7有可能会有这个崩溃
                                 |                 "Auto Layout still required after executing -layoutSubviews” iOS7上崩溃sdk缺陷 点击
                                 |                layoutSubviews在以下情况下会被调用:
                                 |                1、init初始化不会触发layoutSubviews。
                                 |                2、addSubview会触发layoutSubviews。
                                 |                3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
                                 |                4、滚动一个UIScrollView会触发layoutSubviews。
                                 |                5、旋转Screen会触发父UIView上的layoutSubviews事件。
                                 |                6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
                                 |                7、直接调用setLayoutSubviews。
                                 |        每一个视图有唯一的父视图点击。addsubview操作把它从上一个父试图中移除
                                 |        善于使用hidden 使用animateWithDuration简单地控制页面切换效果
                                 |        使用animateWithDuration简单地控制页面切换效果点击
                                 |        简单动画 animateWithDuration点击
                                 |        ★因为UIView没有实现copy协议,因此找不到copyWithZone方法,使用copy的时候导致崩溃,但是我们可以通过归档再解档实现copy,这相当于对视图进行了一次深拷贝

                                 |       UIView事件击穿,扩大按钮响应区域,通过重写hittest方法实现。点击
                                 |->CALayer
                                 |        CALayer是个简单的类,它是用来在屏幕上显示内容展示的矩形区域.容芳志出品点击
                                 |        直接从NSObject继承,少了UIResponder类,固CALayer悲催的不能响应任何用户事件点击
                                 |-> UIWindow
                                 |            
    每一个IOS程序都有一个UIWindow译文
                                 |            UIWindow有三个层级,分别是Normal,StatusBar,Alert点击
                                 |            keyWindow是指定的用来接收键盘以及非触摸类的消息,
                                 |            而且程序中每一个时刻只能有一个window是keyWindow。
                                 |-> UIImage
                                 |        加载图片几种方式点击
                                 |            [UIImage imageNamed:@“xxx”] 系统缓存到cache中
                                 |            [UIImage imageWithContentsOfFile:path] 不缓存
                                 |            [UIImage imageWithData:data]  不缓存
                                 |           ★ 拉伸图片,四角保持不变 resizableImageWithCapInsets:
                                 |           ★ 加载gif图片点击
                                 |-> UILabel点击
                                 |            没有居上居下对齐,可以使用TTTAttributedLabel
                                 |           ★   重写drawTextInRect:方法,可以自定义绘制区域,比如可设置Inset
                                 |            [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.textInsets)];                            
                                 |           ★  设置行间距,通过设置label的attributedText来实现

                              /    
            /-> UIKit 
            |                 \                  
            |                    |-> UIButton

            |                    |            设置颜色,文字一定要指定button状态
            |                    |            善于使用contentEdgeInsets,imageEdgeInsets titleEdgeInsets可以设置文本边距点击
            |                    |            设置圆角可layer.cornerRadius
            |                    |            UIButton 设置 imageView frame是无法改变大小的,大小就是图片的大小【点击】
            |                    |            设置button上的title左对齐。仅仅设置label是没用的,需要:

            |                    |            ★ btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

            |                    |            去掉系统的按下高亮置灰效果 [btn setAdjustsImageWhenHighlighted:NO];

            |                    |-> UITextfield 
            |
                        |        隐藏键盘,[textfield resignFirstResponder]
            |                    |        ★ 任意页面隐藏键盘点击
            |                    |-> UIScrollerView
            |
                        |        上拉下拉原理点击
          |                  |        Apple不建议在UIScrollerView上添加UITableview Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.
            |                    |-> UITableView
            |
                        |        复用,注意重写 - (void)prepareForReuse
            |                    |        ★ 在-(void)layoutSubviews中设置subview的frame。否则frame总是(320,44)
            |                    |        dequeueReusableCellWithIdentifier 从重用池中获取,可能是nil
            |                    |        dequeueReusableCellWithReuseIdentifier 同上,但是不会是nil
            |                    |        插入,删除,移动section或item的顺序,需遵循下面两个步骤点击
            |                    |            1. 更新dataSource的数据
            |                    |            2. 调用相应的collection view方法删除或者插入section或item
            |                    |        非常严格的条件:,在更新collection view之前,先更新datasource,
            |                    |        因为collection view总是假设你已经准备好打他source了 否则collection view收到错误的item,并造成crash
            |                    |        右侧音序条点击
            |                    |        UITableView上拉、下拉原理点击
            |                    |        AsyncDisplayKit 流畅的解决方法点击
            |                    |        tableView 在更改dataSource后需要立即调用reloadData,否则只要UI有刷新必crash。
            |                    |        tableView 在调用reloadData后,短时间内不要更改dataSource,尤其是将dataSource清空,否则只要ui有刷新必crash
            |                    |        tableView正在滚动的时候,如果reloadData,偶尔发生App crash的情况点击
            |                    |        UITableview Deceleration 加速滑动(惯性滑动)、弹性回归原理点击
            |                    |        UITableview 刷新某一个cell 或 section点击
            |                    |        UITableview 上拉隐藏搜索框,下拉出现搜索框点击
            |                    |        UITableview 是在willDisplayCell: 还是在cellForRowAtIndexPath: update data 呢?【点击】
            |                    |        UITableview UITableViewStylePlain模式,header不浮动点击

     

            |                    |        UITableview 当tableview的section比较多时候,内容也比较复杂,比如设计多个http接口。在更新tableview的时候一定要注意清除旧数据
            |                    |-> UITableViewCell 
            |                    |        UITableViewCell changes the background color of all sub views when cell is selected or highlighted.意思就是说当UITableViewCell被选中或者高亮的时候,它的所有子view的颜色都会改变。
            |                    |       所以建议一般设置cell.selectionStyle = UITableViewCellSelectionStyleNone;

            |                    |-> UIDevice
            |                    
    |        设备名 [UIDevice currentDevice].name,
            |                    |        系统版本号 [[UIDevice currentDevice].systemVersion doubleValue]; 点击
            |                    |        屏幕旋转方向 [[UIDevice currentDevice] orientation]
            |                    |        区分iPad还是iPhone [UIDevice currentDevice].userInterfaceIdiom);
            |                    |-> UIScreen
            | 
                     |        如何正确的绘制1像素的线点击
            |                  |        保证边距不变,内容等比例拉伸点击
            |                  |-> UIEdgeInsets
            |                    |       
    实际显示边距,跟设置边距的距离点击
            |                    \->自动布局
            |                             
    Masonry 高级一点用法【多个label,可变长情况下使用Masonry】点击
            |                             storyboard
            |                             在autolayout之前还有一种技术叫autoresizingmask,功能少一些。兄弟视图之间约束比较费劲
            |
            |                    /-> NSObject 既是对象也是协议,可以将对象自动置nil 比如 int = 0 bool = NO
            |                  |      几乎所有类的基类或者协议点击
            |                 |        类对象:程序中第一次使用该类的时候被创建,在整个程序中只有一份(类的实例则有多份)此后每次使用都是这个类对象,它在程序运行时一直存在点击

            |                 |        isKindOfClass:和isMemberOfClass:,通过这两种方法可以确定一个类的从属关系\
            |                 |               后者测试一个接收器是否是一个指定类的实例;而后者可以测试类的从属关系。
            |                 |       respondsToSelector: 方法测试一个接收器是否通过selector实现(implements)了一个标志符话的方法
            |                 |       description方法,允许一个对象返回一个字符串来描述它的内容;这个常用于调试debug
            |                 |       encodeWithCoder: 和 initWithCoder:方法,NSCoding协议中仅有的组成成员\
            |                 |               第一个允许对象编译它的实例变量,第二个允许一个对象初始化它自身的解码实例变量。
            |                 |       conformsToProtocol:方法,测试接收器(对象或者类)符合一个给定的协议(protocol)
            |                 |       类对象中的 isa 指向类结构被称作 metaclass点击跟[object class]有点区别,比如KVO的时候
            |                 |       __weak如何实现对象值自动设置为nil的点击

           |                 |       如何判断两个对象相等,需要重写isEqual:方法和hash方法。虽然hash是为了对象加入set或者你是NSArray时候用的。但是判断两个对象是否相等,可以先hash,如果hash都不一样那么肯定不一样,接下来才是isEqual:方法的比较点击。使用hash只是提高判断效率。

            |                 |       任何 Objective-C 都有 hash 方法,该方法返回一个 NSUInteger,是该对象的 hashCode单击

            |                 |       任[self class]和 [super class]问题:self 是类的隐藏的参数,指向当前当前调用方法的类;super并不是隐藏的参数,它只是一个“编译器指示符”,它和self指向的是相同的消息接收者。所以两者都指向本类。点击
            |                 |-> NSString & NSMutableString
            |                    |       
    NSString作为属性时候,用copy还是strong修饰?如果只是NSString没什么copy和strong区别。
            |                    |      当NSString对象指向NSMutableString的时候,strong是单纯的增加对象的引用计数,而copy操作是执行了一次深拷贝点击】
            |                 |-> NSArray & NSMutableArray
            |                    |
           NSArray 各种遍历方式,倒序遍历点击
            |                    |       NSArray简便初始化方法@[@"1",@"2"];
            |                    |       浅拷贝。数组本身使用地址,但是数组item仍是旧对象Apple 官方解释点击
            |                    |           无论copy、arrayWithArray、copyWithZone 数组内对象并没有变。
            |                    |           只是copy出来的array是新地址,arrayWithArray出来的数组也是新地址。
            |                    |       深拷贝。数组本身使用地址,但是数组item是新地址
            |                    |           [[NSArray alloc] initWithArray:someArray copyItems: YES]; 
            |                    |           深拷贝时候,数组中的item必须实现NSCopying协议并实现copyWithZone:
            |                    |       防止NSArray was mutated while being enumerated
            |                    |       array包含array的情况深拷贝。NSArray* trueDeepCopyArray = [NSKeyedUnarchiver \        
            |                    |               unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
            |                    |       containsObject 注意:在对比数组中元素的时候,调用元素的isEqual的返回值。
            |                    |-> NSDictionary & NSMutableDictionary
            |                    |       取值时候,最好判断object的类型。    if ([object isKindOfClass:[NSString class]]){ //todo};
            |                    |-> NSNumber 和 NSInteger NSRange
            |                    |          前者专门用来装基础类型的对象,把整型、单精度、双精度、字符型等基础类型存储为对象
            |                    |-> NSNull  FMDB数据库,使用的时候崩溃
            |                    |           JsonKit转换以后会生出相应的[NSNull null]对象点击
            |                    |-> NSData 字节缓冲区
            |                    |          + (nullable instancetype)dataWithContentsOfURL:(NSURL *)url
            |                    |          dataWithContentsOfURL 虽然是同步的,但可以结合gcd 异步加载网络图片点击
            |                    |-> NSUserDefaults点击
            |                    |            可用于APP setting 默认值不好用,SDK bug 
            |                    |            设置WebVIew的UA点击
            |                    |-> NSDate & NSDateFormatter & NSCalendar
            |                    |            可判断过去几个小时,还是几天 - (NSDateComponents *) components:fromDate:toDate:options:
            |                    |           可获取时间戳
            |                    |           有时候有8小时的时差,解决办法点击

            |                    |           在开发iOS程序时对日期处理的总结点击
            |                    |           当新的一天来到,或者说当运营商时间更新的时候,UIApplication会下发一个通知:UIApplication-SignificantTimeChangeNotification

            |                    |           当系统的区域格式,或者时间格式(是否24小时制)改变时,下发通知:NSCurrentLocale-DidChangeNotification

            |                    |-> NSCoding & NSCoder 仅有的两个方法,数据的序列号和反序列化点击       
            |                    |            - (void)encodeWithCoder:(NSCoder *)aCoder;
            |                    |            - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
            |                    |-> NSCopying & NSZone
            |                    |          + (instancetype)allocWithZone:深拷贝,类似于memcpy这样的C方法点击
            |                    |-> NSAutoreleasePool
            |                    |          降低内存峰值点击
            |                    |          在Runloop休眠前(kCFRunLoopBeforeWaiting)时候释放自动释放池中的对象
            |                    |-> NSFileManager 删除文件的时候先判断是否存在是个好习惯
            |                    |-> NSTimer
            |                    |
            NSTimer 简单使用 点击
            |                    |        ★ NSTimer定时器时间并不精确,类似于公交车进站,堵车就不准时点击
            |                    |-> NSLog暴力打印,常用于测试点击
            |                    |-> NSClassFromString  从字符串获取类。NSStringFromClass,从类名获取字符串
            |                    |        ★ 不要小瞧这两个API,配合使用,他可以做到代码逻辑解藕的效果。
          |                /    
            |-> Foundation      
            |                 \
        
            |                    |-> NSIndexPath 链式结构;tableview用的比较多点击
            |                    |           初始化 [NSIndexPath indexPathForRow:0 inSection:1];
            |                    |-> NSError 网络变成经常用到
            |                    |-> NSException
            |                    |-> NSStringEncoding NSString的编码格式,了解即可点击
            |                    |-> NSProgressIndicator
            |                    |-> NSBundle 是个目录,包含了程序使用的资源,如图像,声音,编译好的代码,nib文件点击
            |                    |-> NSNetServiceBrowser
            |                    |-> NSValue 可以包装任意一个对象,可以用NSValue将struct存到NSArray和NSDictionary中。点击

     

            |                    |-> NSURLConnection iOS9已不再使用
            |                    |-> NSURLSession & NSURLSessionTask 点击NSURLSession提供的功能:
            |                    |            通过URL将数据下载到内存点击
            |                    |            通过URL将数据下载到文件系统
            |                    |            将数据上传到指定URL
            |                    |            在后台完成上述功能点击
            |                    |-> NSURLRequest 包装了网络请求的信息点击
            |                    |-> NSInputStream & NSOutputStream socket编程点击 
            |                    |-> NSPredicate 
            |                    |            谓语查询,原理和用法都类似于SQL中的where点击
            |                    |-> NSLayoutConstraint 现在都用masonry
            |                    |-> NSLock & NSRecursiveLock & NSCondition 多线程锁
            |                    |          最基本的同步锁点击
            |                    |          @synchronized{//todo} 同样也是同步锁点击
            |                    |          事实上信号量也能实现锁的目的,信号量和锁的区别点击第二篇点击
            |                    |-> NSMethodSignature        
          /                      |         配合NSInvocation实现消息转发点击
    iOS                       |-> NSInvocation 直接调用 某个对象的消息点击
          \                      |          iOS中可以直接调用 某个对象的消息 方式有2种performSelector:withObject: 和NSInvocation
            |                    |          当然,还以用C语言的函数指针,参见下面的“方法调配技术
            |                    |-> NSSet 无序的对象集合,用处少
            |                    |-> NSUrl 基本使用,包含File URL和File path点击
            |                    |-> AVPlayer基本使用点击
            |                    |           获取视频时间长度 点击
            |                    \-> NSNotificationCenter 同步的机制点击注意防止重复,相似的机制还有delegate,observer,block
            |
            |                    /-> 创建push原理介绍、证书制作、测试push 专辑 点击
            |                    |       "iOS push全方位解析(一)【译文】"——iOS PUSH概述点击
            |                    |       "iOS push全方位解析(二)【译文】"——生成OpenSSL证书,Provisioning Profile点击
            |                    |       "iOS push全方位解析(三)【译文】"——一个极简的demo,并测试一下push点击
            |               /
            |-> Push         
            |               \
            |                    |
           
     iOS6、7、8、9 Push的演化 点击,但目前还是不尽人意(APP 无法获取通知栏消息数目)
            |                    |       ★ php写的可以在本机发送iOS push程序点击
            |                    |        iOS7 Background Remote Notification(后台远程通知——静默push)点击
            |                    \-> 有一些三方push SDK:极光push
            |

            |-> block 必须掌握
            |             block专辑点击;Block带有局部变量的匿名函数;iOS开发尤其实用
            |              【block编程第一篇】 block编程热点介绍(官方文档翻译的)点击
            |              【block编程第二篇】 block捕获变量和对象点击
            |              【block编程第三篇】block内存管理——如何验证block在栈上,还是堆上点击
            |              【block编程第四篇】block的实现点击
            |              【block编程第五篇】block中使用 weak–strong dance 技术避免循环引用点击
            |-> 多线程
            |            iOS有三种多线程编程的技术,分别是:点击
            |                 1、NSThread 下面会讲到
            |                 2、Cocoa NSOperation 下面会讲到
            |                 3、GCD 下面会讲到
            |                这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单。
            |            dispatch_once 执行一次,用于创建单例点击可满足线程安全
            |           iOS 不像C++ 那样,可以直接将构造函数设成private所以创建绝对单例模型需重写allocWithZone,点击
            |                
            |                       /-> 引用计数(retainCount)
            |                       |       retain 引用计数+1 对象alloc时,引用计数为1, release引用计数-1.引用计数=0时候,真正释放
            |                       |       autoRelease,自动释放对象点击
            |                       |-> 便捷构造方法 iOS
            |                       |          对象在自动释放池中,不需要开发者手动释放,比如下面的方法
            |                       |          NSString的stringWithString
            |                       |          NSArray的arrayWithObjects:和arrayWithArray:
            |                       |          UIImage的imageNamed:
            |                       |-> 内存管理高级指南官方译点击
            |                       |-> 内存管理实践点击
            |                     /
            |-> 内存管理专栏点击
            |                     \
            |                       |-> MRC
    手动引用计数。release和retain成对儿
            |                       \->ARC 自动引用计数
            |                            强烈建议使用ARC
            |                            禁止在函数内返回局部变量指针,不然就是野指针!
            |                            容易引起循环引用的地方点击
            |                            - (id)performSelector:(SEL)aSelector withObject:(id)object;引起警告
            |                                    warning:performSelector may cause a leak because its selector 点击
            |
            |-> 进程间通信(APP间通信)点击】【点击
            |                 iOS可通过URL Scheme,调用别的APP(iOS内的应用调用协议),APP 实现 - (BOOL)application: openURL: options: 
            |
            |                            /-> Runtime 运行时特点《运行时之一:类与对象》南峰子出品 点击
            |                            |        Objective-C程序员可以在程序运行时创建,检 查,修改类,对象和它们的方法点击
            |                            |        Objective-C runtime库也负责找出方法的最终执行代码
            |                            |        class  Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。
            |                            |                struct objc_class {
            |                            |                    Class isa  OBJC_ISA_AVAILABILITY;
            |                            |                #if !__OBJC2__
            |                            |                    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
            |                            |                    const char *name                        OBJC2_UNAVAILABLE;  // 类名
            |                            |                    long version                                 OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
            |                            |                    long info                              OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
            |                            |                    long instance_size                       OBJC2_UNAVAILABLE;  // 该类的实例变量大小
            |                            |                    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
            |                            |                    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
            |                            |                    struct objc_cache *cache             OBJC2_UNAVAILABLE;  // 方法缓存
            |                            |                    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
            |                            |                #endif
            |                            |                } OBJC2_UNAVAILABLE;       
            |                            |                1. isa:所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass
            |                            |                2. super_class:指向该类的父类,如果该类已经是最顶层的根类,则super_class为NULL。
            |                            |                3. cache:用于缓存最近使用的方法。提高方法查找效率
            |                            |        objc_object与id objc_object是表示一个类的实例的结构体
            |                            |                struct objc_object {
            |                            |                    Class isa  OBJC_ISA_AVAILABILITY;
            |                            |                };
            |                            |                typedef struct objc_object *id;
            |                            |           当创建一个类的实例对象时,分配的内存包含objc_object数据结构,然后是类的实例变量的数据。
            |                            |           NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。
            |                            |           另外还有我们常见的id,它是一个objc_object结构类型的指针。id 其实就是一个 struct objc_object 类型的指针。但是 id 不是 NSObject * ,为什么可以指向任意的 NSObject 对象呢?因为 objc_object 只有一个 Class 类型的 isa 变量,而这个结构,恰恰和 NSObject 的定义一致
            |                            |        meta class元类,是一个类对象的类;它存储着一个类的所有类方法。
            |                            |           当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;
            |                            |           而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。

            |                            |        继承体系点击
            |
                                |        动态创建类点击
            |                            |            objc_setAssociatedObject点击给对象增加属性,一般配合类别使用        
            |
                                |            object_getClass  得到一个实例的类点击
            |                            |            objc_copyImageNames  获取指定类所在动态库南峰子出品点击
            |                            |            objc_copyClassList  创建并返回一个指向所有已注册类的指针列表点击
            |                            |        class_xxx系列函数点击
            |                            |            class_copyPropertyList  获取类的属性
            |                            |            class_addMethod 为类添加方法 
            |                            |            class_isMetaClass 判断是否为元类
            |                            |            class_getName 获取类名
            |                            |            class_copyIvarList 拷贝类的实例变量列表,注:这里特别要指出的是实例变量列表中的实例变量的定义如下,它包含了变量的名称、类型、偏移等,但却不包括变量的值-----值在对象而非类中
            |                            |            class_getInstanceMethod 获取实例方法
            |                            |-> Runnloop  ibireme出品 点击
            |                            |        RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息
            |                            |        并提供了一个入口函数来执行上面 Event Loop 的逻辑
            |                            |        Run Loop并非iOS平台专属的概念,在任何平台的多线程编程中,为控制线程生命周期点击
            |                            |        接收处理异步消息,都需要类似Run Loop的循环机制来实现:从简单的一个无限顺序
            |                            |        do{sleep(1);//执行消息}while(true),到高级平台,如Android的Looper,都是类似的机制。
            |                            |        放在下一个runloop执行,保证当前执行正确【点击】
            |                            |       Runnloop基本作用  点击
            |                            |        ·保持程序的持续运行(比如主运行循环)
            |                            |        ·处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
            |                            |        ·节省CPU资源,提高程序性能:该做事时做事,该休息时休息
            |                            |       Runnloop应用
            |                            |        ·NSTimer 默认是NSDefaultRunLoopMode,滑动时候定时器不计时
            |                            |        ·ImageView显示 当用户在拖拽时(UI交互时)不显示图片,拖拽完成时显示图片
            |                            |        ·PerformSelector  设置运行模式
            |                            |        ·常驻线程 经常在后台进行耗时操作,如:监控联网状态,扫描沙盒等 不希望线程处理完事件就销毁,保持常驻状态
            |                            |        ·自动释放池 在休眠前(kCFRunLoopBeforeWaiting)进行释放,处理事件前创建释放池,中间创建的对象会放入释放池
            |                      |       PerformSelecter 当调用 NSObject 的 performSelecter:afterDelay: 后,实际上其内部会创建一个 Timer
            |                         |                 并添加到当前线程的 RunLoop 中;所以如果当前线程没有 RunLoop,则这个方法会失效点击
            |                          /
            |-> iOS 动态机制
            |                          \ 

            |                            |->  OC .(点)与->(箭头)用法区别。前者是访问setter和getter方法,后者是直接访问变量。
            |                            |-> 消息传递 objc_msgSend点击南峰子出品 点击
            |                            |           obj-c脱胎于smalltalk的消息处理。所有方法调用都是发消息。消息是啥?一串字符点击
            |                            |           如果向某对象传递消息,那就会使用动态绑定机制来决定需要调用的方法
            |                            |           objc_msgSend有两个隐藏参数,消息接收对象 方法的selector ,即(self,_cmd)
            |                            |-> 消息转发 message forwarding点击        
            |                            |            就是对象在接收到无法解读的消息之后会发生什么情况
            |                            |            (1) +(BOOL) resolveInstanceMethod:(SEL)selector 类是否新增一个实例方法
            |                            |            (2) resolveClassMethod 是否新增了类方法
            |                            |            (3) -(id) forwardingTargetForSelector:(SEL)selector 能不能把这条消息转给其他接收者来注册 
            |                            |            (4)-(void) forwardInvocation:(NSInvocation*)invocation  消息派发系统
            |                            |            (5)最后若都不能处理消息,则doesNotRecognizeSelector: 会抛出异常
            |                            |            当我们不能确定一个对象是否能接收某个消息时,会先调用respondsToSelector:来判断一下
            |                            |-> SEL点击
            |                            |            SEL又叫选择器,是表示一个方法的selector的指针,每一个方法都对应着一个SEL。
            |                            |            OC在编译的时候,会根据方法的名字(包括参数序列),生成一个用 来区分这个方法的唯一的一个ID
            |                            |                这个ID就是SEL类型的。需要注意的是,只要方法的名字(包括参数序列)相同,那么它们的ID都是相同的。
            |                            |                就是 说,不管是超类还是子类,不管是有没有超类和子类的关系,只要名字相同那么ID就是一样的
            |                            |            方法的定义体里面,我们可以通过访问_cmd得到这个方法自己的SEL。 
            |                            |-> 方法调配技术 method swizzling 用于调试南峰子出品点击
            |                            |            IMP 它是objetive-C 方法(method)实现代码块的地址,实际上是函数指针,指向方法实现的首地址
            |                         |                IMP imp = [requestItem.delegateTarget methodForSelector:selector];
            |                         |                void (*func)(id, SEL, ResponseItem *) = (void *)imp;
            |                          |                func(requestItem.delegateTarget, selector, responseItem);
            |                            |            可以从selector获取IMP,比如:- (IMP)methodForSelector:(SEL)aSelector;
            |                            |            Swizzling应该总是在+load中执行
            |                           \-> 事件响应链点击另外一篇点击
            |                                        在 iOS 中,几乎所有类都是 responder,比如 UIWindow、UIView、UIControl、UIControllers 等
            |                                        当手指去触摸屏幕上 UIView 的实例对象 aView。产生一个触摸事件 UIEventTypeTouches
            |                                        而接收触摸事件的对象 aView,就是一个 responder object。
            |                                        initial view –> super view –> …..–> view controller –> window –> Application –> AppDelegate
            |                        
            |
                                  /-> 沙盒(Sandbox)iOS沙盒机制容芳志出品点击
            |                              |        每个应用程序都有自己的存储空间
            |                              |         应用程序不能翻过自己的围墙去访问别的存储空间的内容
            |                              |         应用程序请求的数据都要通过权限检测,假如不符合条件的话,不会被放行。
            |                           |-> Group iOS8+数据共享,例如扩展(Extension)共享数据点击
            |                           |-> Spotlight iOS9+ 系统搜索。官方demo点击
            |                           |-> GCD(Grand Central Dispatch) iOS开发有一个强有力的多线程工具 点击
            |                              |            多线程入门raywenderlich出品 点击        
            |                              
    |            系统提供一个叫做 主队列(main queue)
            |                              |            系统还提供一个叫做全局调度队列(Global Dispatch Queues)有四个优先级
            |                              |            开发者自己创建队列(串行,或者并行)
            |                              |            至少有五个队列任你处置:主队列、四个全局调度队列,再加上任何你自己创建的队列。
            |                              |            GCD 深入理解:第一部分点击
            |                              |            GCD 深入理解:第二部分点击
            |                              |            开发常见方法介绍
            |                              |                  dispatch_after 延后工作
            |                              |                  Dispatch Groups 会在整个组的任务都完成时通知你
            |                              |            dispatch_semaphore_t  信号量,让你控制多个消费者对有限数量资源的访问。点击
            |                              |            dispatch_semaphore_wait  使得信号量-1,当=0时候阻塞
            |                              |            dispatch_semaphore_signal  释放信号量,即信号量+1
            |                              |            信号量也可以实现两个异步操作,都完成时(即相互等待)。再执行一些操作。
            |                              |            
            |                              |-> CoreData数据持久化,相比sqlite有下面优势点击
            |                              |          数据库字段或者表有更改会导致crash,CoreData的版本管理和数据迁移变得非常有用,\
            |                              |          手动写sql语句操作还是麻烦一些。
            |                              |          不光能操纵SQLite,CoreData和iCloud的结合也很好,如果有这方面需求的话优先考虑
            |                              |          并不是直接操纵数据库,比如:使用CoreData时不能设置数据库的主键,目前仍需要手动操作。
            |                              |          效率上其实跑程序时感觉不出来,毕竟手机上的数据不能跟网站的数据和访问量相提并论。
            |                           /
            |-> 特殊封装&平台特性
            |                           
    \  
            |                          |-> 类别(Category)扩展(Extension)的
    区别点击extension是在编译期的,它就是类的一部分;category是运行时期决议的,工作原理点击
            |                              |         堪称iOS编程的精髓点击念茜出品点击
            |                              |-> KVC 键值编码
            |                              |          在IOS的中,没有绝对的私有,包括方法和变量,可以通过字符获取属性点击
            |                           |-> KVO 键值观察,依赖isa-swizzling技术王中周出品 点击
            |                           |        依赖Runtime 和KVC 一个新的类会动态被创建。详细原理点击另外一篇点击
            |                           |        同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。
            |                           |        然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,
            |                           |        因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制
            |                           |        Person在建立KVO监听前和之后的打印输出 self->isa:Person    [self class]:Person 
            |                               |                    self->isa:NSKVONotifying_Person   [self class]:Person  
            |                           |        比如:Tableview上拉下拉动画检测offset;播放视频,获取视频时长时候等
            |                           |        为什么KVO不成对儿调用,会崩溃?
            |                           |-> 多任务
            |                               |      
    后台运行一段时间(不是地图,voip类app)点击
            |                           |-> 3D Touch ,通过在plist中添加菜单,然后app实现下面的方法。进入APP
            |                           |               - (void)application: performActionForShortcutItem: completionHandler:
            |                           |-> spotlight 通过系统搜索,进入APP点击
            |                           \-> Touch ID 如何使用iOS 8 指纹识别,代码、实例点击
            |-> HTTPs  
            
    |                 建立安全链接
            |                         之前做过一段IM,对基本建立安全链接略知一二点击
            |                 HTTPS进阶点击】【本人总结
            |                         一句话概括https的ssl加密过程:整个加密过程涉及:非对称加密和对称加密两种技术,其中非对称加密
            |                         (由于RSA计算速度特别慢,无法对大量信息加密)用于简历安全链接,确保server和客户端
            |                          的合法(这需要证书机制);对称加密,则基于刚刚的安全链接之上,对传输内容的加密(加密速度很快)
            |                         整个过程需要4次握手
            |
            \-> iOS工具
    转屏。APP本身是竖屏,但是某一个页面需要横屏点击
                    CrashHlytics Crash统计工具
                    AFNetworking 和 ASIHttp
                    SDImage
                    TMCache
                    AsyncDisplayKit 是 Facebook 推出的用于保持界面流畅性的框架
    ------------------------------------------------------------------------------------------
            参考文献:《Objective-C高级编程:iOS与OS X多线程和内存管理》日本人写的;
             《Effective Objective C 2.0:编写高质量iOS与OS X代码的52个有效方法》;
             《Objective-C基础教程(第2版)》        

    网络博客参考(无循序):念茜、南峰子、ibireme、容芳志、唐巧、王巍、董柏然、阮一峰、一片枫叶,王中周,颐和园等博主

    参考的公众帐号:《iOSDevTips》即唐巧的公众帐号;《iOSDevTip》

     

    完整的UIKit和Foundation 结构 <点击>

    展开全文
  • 感觉好久没写会动的Demo了,前几天写了很久的Block源码分析,分析了几天整个人都不好了,都不知道block是什么了......,有需要的同学可以去看看,简直不要太简单Block是什么鬼  毕竟也是做电商的,有时候会研究...

    感觉好久没写会动的Demo了,前几天写了很久的Block源码分析,分析了几天整个人都不好了,都不知道block是什么了......,有需要的同学可以去看看,简直不要太简单Block是什么鬼毕竟也是做电商的,有时候会研究别人家的App实现,有写过Higo的页面,也看了小红书的push动画,之前一直不知道怎么做到的,偶然间看到了转场动画自定义,原来是这么玩的,OK,今天以非常简单的方式带大家入门转场动

    老规矩,没图说个毛线,先看会儿动画在决定是否继续看。。。。。。

        

    TNND,为什么只能上传2M的图!!!!!!





    转场其实就是下一场景的VC视图替换当前场景VC视图以及控制器的过程,我们看到的系统自带的就是当前视图消失了,下个视图出现,这是非常基本的动画了转场动画不言而喻,最重要的其实是动画,学习了几天,简单分析下两种情况

    1.就是最常见的UINavigationController中的push和pop

    2.Modal转场,present以及dissmiss,支持的模式不多,UIModalPresentationCustom和   

       UIModalPresentationFullScreen



    根据上面说的两种,也是最常用的,我们来自定义一下,看看能搞成什么样子。

    Apple分离了很多协议出来支持转场动画,我们不深入研究,就用最简单的两种来实现,而且我只介绍我用到的代理,不用的就不BB了,不然看起来很乱
    1.转场代理

    <UINavigationControllerDelegate>  对应UINavigationController delegate属性遵守该协议
    <UIViewControllerTransitioningDelegate> 对应UIViewcontroller的transitioningDelegate属性遵守该协议


    2.动画控制器(最核心的就是他了)
    <UIViewControllerAnimatedTransitioning>
    我们在这里通过转场上下文transitionContext来获取我们需要的View,然后可以添加视图以及执行动画


    3。转场环境(这个是系统已经带上了,我们知道就好)
    <UIViewControllerContextTransitioning>就是上面动画控制器获取的对象,提供了转场需要的数据和交互


    知道有这三个代理,我们来简单举个例子,这样看起来舒服点

    我们先拿UINavigationController举个例子
    首先我们需要有个类来实现转场代理,有两个方法
    第一:我们用一个一个UINavigationController的子类,来实现转场代理。在代理方法里面返回对应的动画对象
    第二:我们可以弄一个NSObject的类型,实现转场代理,代码写的话可以在外部弄个属性强引用封装的代理对象,用storyBoard的话直接在IB页面拖个NSObject
    类型的东东,和拖View一样拖进去就强引用了,然后把类型设置为刚才封装的代理对象就好了

    然后我们看到这个方法是需要一个实现<UIViewControllerAnimatedTransitioning>协议的动画对象,就创建一个NSObject实现这个代理方法
    这里有两个,一个是转场时间,一个就是真正的转场动画的实现方法,这里你就需要转场环境transitionContext进行布局以及动画交互,然后把你需要的动画写出来就好了



    再拿UIViewcontroller的present来举个例子
    首先一样,我们需要实现转场代理,这里也有很多方法
    第一:让self成为transitioningDelegate的代理,然后实现转场代理,同样里面返回对应的动画对象
    第二:用UIPresentationController系统提供的类来全权保管需要的两个转场代理和动画代理,这类能管理view的各种属性和时间点,我们只需要present的时候
    把代理只想继承于UIPresentationController对象的子类就好了,然后我们需要实现的动画就出来了


    针对上面举得两个例子,我们等下分别介绍第一种方法




    根据图片来看,push和present还是有结构上的区别的,有个点要特别注意,不然你的页面就黑了

    push和present其实不只是上面代理的区别,我们在实现UIViewControllerAnimatedTransitioning这个协议的动画控制器里面通过转场环境来操作的时候就需要注意了

    push操作的转场动画在动画结束之后,presenting(当前页面)是跟着消失了,但是present就蛋疼了,有两种情况,当在这个模式下的时候UIModalPresentationFullScreen和push一样,会先移除视图,然后dismiss的时候后再重新进来,当在UIModalPresentationCustom的时候,看上面的图来说就是presneting未参与转场,所以动画结束之后它未移出视图结构,在dismiss的时候,就会有差异。

    差异就是,当我们push还是pop的时候都会从转场环境

    (id<UIViewControllerContextTransitioning>)transitionContext拿出toView来,然后add到containerView里面

    虽然我也不知道这里containerView是怎么工作的......如果是UIModalPresentationCustom这个模式下dismiss的时候,你再add进去,就黑了,他本身就不会参与转场,而且也不会从视图结构中移除,所以这个点还是要小心


    知识点:

    1.小红书push转场动画以及图片上的小动画

    2.present自定义小窗口模式的动画

    3.离子发射器做下雪动画

    4.碎屏美女

    5.还有一个非常简单的cell切换以及瀑布流


    第一步:瀑布流搭建以及下雪动画

    瀑布流的效果这里不详细介绍了需要的同学请戳我另一篇点击打开链接

    下雪动画这个东西我用的是CAEmitterLayer和CAEmitterCell这套东西做的,本来这东西我是做成点赞之后爆炸的效


    但是改着改着感觉能发射特效,还是蛮好玩的,就改了下属性,就能下雪了,只要记住cell是小颗粒,layer是容器,类似于tableView的cell,这样想去改属性就能得到自己想要的效果了

    self.clipsToBounds = NO; // 让例子能弹出固定的框框,不然只有在框框内而已
        self.userInteractionEnabled = NO; // 取消交互,不然点不到
        CAEmitterCell *cell = [CAEmitterCell emitterCell];
        cell.contents = (id)[UIImage imageNamed:@"favorite_hl"].CGImage; // 这里要的是CGImage
        cell.name = @"snow";
        cell.lifetime = 10.0f;
        cell.lifetimeRange = 100.0;
        // 隐掉的时间
        // 初始化右多少个
        cell.birthRate = 10;
        cell.velocity = 10.0f; // 越大越往外 速度越快
        cell.velocityRange = 10.0f; // 越小就越接近圆形,越大越不规则
        cell.emissionRange = M_PI_2; // 发散的范围
        cell.yAcceleration = 2;
        cell.scale = 0.5f; // 栗子倍数
        cell.scaleRange = 0.02;
        
        
        _emitterLayer = [CAEmitterLayer layer];
        _emitterLayer.emitterShape = kCAEmitterLayerLine; // layer的形状
        _emitterLayer.emitterMode = kCAEmitterLayerSurface; // layer的弹出方式
        _emitterLayer.emitterSize = CGSizeMake(self.bounds.size.width * 2, 100);
        _emitterLayer.renderMode = kCAEmitterLayerOldestFirst;
        _emitterLayer.masksToBounds = NO;
        _emitterLayer.emitterCells = @[cell];
        _emitterLayer.frame = [UIScreen mainScreen].bounds;
        _emitterLayer.emitterPosition = CGPointMake(100, -40);
        
        [self.layer addSublayer:_emitterLayer];


    第二步:实现push自定义转场动画前代理设置

    1.自定义UINavigationController的子类,实现UINavigationDelegate

    - (void)pushViewController:(UIViewController *)viewController
                     imageView:(UIImageView *)imageView
                        desRec:(CGRect)desRec
                      original:(CGRect)originalRec
                      deleagte:(id<MKJAnimatorDelegate>)delegate isRight:(BOOL)isRight;
    根据属性也能看出,我们自定义的方法把原来的位置,目标位置,图片以及presentedVC传进去了,VC作为参数是之后设置代理用的


    2.实现NavigationDelegate的方法 返回自定义动画控制器

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController *)fromVC
                                                     toViewController:(UIViewController *)toVC
    {
        // 普通push的时候就是小红书类型的
        MKJAnimator *animator = [[MKJAnimator alloc] init];
        animator.imageView = self.imageView;
        animator.destinationRec = self.destinationRec;
        animator.originalRec = self.originalRec;
        animator.isPush = self.isPush;
        animator.delegate = self.animationDelegate;
        
        // 左侧push的时候是屏幕碎裂类型的
        MKJSuperAnimation *superAnimator = [[MKJSuperAnimation alloc] init];
        
        if (self.isRight) {
            return animator;
        }
        else
        {
            return superAnimator;
        }
    }


    第三步:实现Push真正的自定义转场控制组件

    1.创建一个对象遵循<UIViewcontrollAnimatedTransioning>代理,并生成一个动画的结束代理,让presented(push过去的VC)控制器来实现,让动画结束的时候做一系列操作

    @protocol MKJAnimatorDelegate <NSObject>
    
    - (void)animationFinish;
    
    @end
    
    @interface MKJAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @property (nonatomic,strong) UIImageView *imageView;
    @property (nonatomic,assign) CGRect destinationRec;
    @property (nonatomic,assign) CGRect originalRec;
    @property (nonatomic,assign) BOOL isPush;
    @property (nonatomic,assign) id<MKJAnimatorDelegate>delegate;
    
    @end

    2.实现动画的核心代理方法持续时间和动画效果(核心代码)

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        // 获取上面那张图的containerVIew
        UIView* contentView = [transitionContext containerView];
        contentView.backgroundColor = [UIColor whiteColor];
        // toView就是push过去的View
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        // 加到容器View里面
        [contentView addSubview:toViewController.view];
        // 先设置为透明
        toViewController.view.alpha = 0;
        
        // 弄一个做动画的UIImageView
        __block UIImageView *imageView = [[UIImageView alloc] initWithImage:self.imageView.image];
        imageView.frame = self.isPush ? self.originalRec : self.destinationRec;
        [contentView addSubview:imageView];
        
        if (!self.isPush) {
            self.imageView.alpha = 0;
        }
        
        // 让临时的ImageView根据坐标动起来 然后把toView也渐渐显示
        [UIView animateWithDuration:0.5 animations:^{
           
            imageView.frame = self.isPush ? self.destinationRec : self.originalRec;
            toViewController.view.alpha = 1.0f;
            
        } completion:^(BOOL finished) {
            // 动画结束必定要告知这个对象结束了,不然问题
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            [imageView removeFromSuperview];
            if (!self.isPush) {
                self.imageView.alpha = 1;
            }
            else
            {
                // 告诉代理结束了
                if (self.delegate) {
                    [self.delegate animationFinish];
                }
            }
            imageView = nil;
        }];
    }


    第四步:实现Present Modal效果的自定义动画小弹窗


    1.这里接着刚才的效果,动画结束之后先给个图片,然后实现小小的动画

    // <MKJAnimatorDelegate> 代理的实现,通知动画结束
    - (void)animationFinish
    {
        // 图片往上平铺
        [self.mainImageView sd_setImageWithURL:[NSURL URLWithString:self.redBookModel.img]];
        
        // 然后做个简单的小动画显示圆点,直线和文字
        [self showAnimationTag];
    }
    2.点击右上角实现present自定义小弹窗

    还是两步走,先实现UIViewControllerTransioningDelegate,让自身成为代理,而且也可以看到,和刚才一样返回一个自定义的动画组件即可

    - (void)click1:(UIButton *)button
    {
        ThirdViewController *thirdVC = [[ThirdViewController alloc] init];
        thirdVC.modalPresentationStyle = UIModalPresentationCustom; // 貌似只支持几种模式,自己写还是直接用custom好了
        thirdVC.transitioningDelegate =  self; // 自己成为代理,返回动画
        [self presentViewController:thirdVC animated:YES completion:nil];
    }
    
    
    #pragma - present的时候需要的代理方法
    #pragma mark - UIViewControllerTransitioningDelegate
    - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        return [MKJPresentAnimator new];
    }
    
    - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {
        return [MKJPresentAnimator new];
    }
    然后再进行关键动画的组装,这里就是刚才提到了push和present的区别,当modal属性是custom的时候,present之后的动画是不会把presentingVC给移出的,那么当dismiss的时候千万别再把toView通过AddSubview到

    ContainerView里面去了

    - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.45f;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        // 这个是present的动画
        UIView *containerView = transitionContext.containerView;
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIView *toView = toViewController.view;
        UIView *fromView = fromViewController.view;
        // 这里present不和push一样需要自己标记,这里直接有跟踪标记
        if (toViewController.beingPresented)
        {
            // toView加进来,设置居中的小框,宽度为1
            
            [containerView addSubview:toView];
            toView.bounds = CGRectMake(0, 0, 1, kScreenHeight *2/3);
            toView.center = containerView.center;
            // 然后再加个蒙层 大小也是很小
            UIView *dimmingView = [[UIView alloc] init];
            dimmingView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3];
            dimmingView.center = containerView.center;
            dimmingView.bounds = CGRectMake(0, 0, kScreenWidth * 3 / 5, kScreenHeight * 3 / 5);
            [containerView insertSubview:dimmingView belowSubview:toView];
            // 动画toView开始变宽  蒙层开始变大
            [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
               
                toView.bounds = CGRectMake(0, 0, kScreenWidth * 3 / 5, kScreenHeight *1/2);
                dimmingView.bounds = containerView.bounds;
                
            } completion:^(BOOL finished) {
                
                [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            }];
            
        }
        else
        {
            // 返回的时候直接放fromView动画缩小就行了,提交之后自动消失了,不需要在进行Add了,不然就黑了
            [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
                
                fromView.bounds = CGRectMake(0, 0, 1, kScreenHeight * 1 / 2);
                
            } completion:^(BOOL finished) {
               
                [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            }];
        }
        
    }

    3.小弹窗里面的用Masonry实现的小动画(按钮旋转缩小以及View扩大)

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        // 给背景蒙层加手势
        for (UIView *dimmingView in self.view.superview.subviews) {
            if (![dimmingView isEqual:self.view])
            {
                [dimmingView addGestureRecognizer:self.tap];
            }
        }
        self.TFWidthConstraint.constant = self.view.bounds.size.width * 2 /3;
        self.labelWidthConstraint.constant = self.view.bounds.size.width * 2 / 3;
        [UIView animateWithDuration:0.3 animations:^{
            self.closeButton.alpha = 1.0f;
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
        }];
    }

    - (IBAction)close:(id)sender {
        self.TFWidthConstraint.constant = 0;
        self.labelWidthConstraint.constant = 0;
        
        CGAffineTransform form = CGAffineTransformMakeRotation(M_PI);
        
        form = CGAffineTransformScale(form, 0.1, 0.1);
        [UIView animateWithDuration:0.8 animations:^{
            self.closeButton.transform = form;
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
            [self dismissViewControllerAnimated:YES completion:nil];
        }];
    }


    第五步:动画组件实现Push自定义的碎屏动画


    依旧是两步走,实现UINavitgationController代理刚才已经介绍了,无非就是弄个代理方法,看了那么多,这个效果其实最关键的还是动画的实现,你脑洞大,那么动画必然就很酷炫,前提是你代码能力比脑洞还大,伪代码

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        // 获取两个VC和对应的View
        1.拿出需要的UIView
        // push是要判断的,present是有属性跟踪的
        2.BOOL isPush 是否push?
        // 截屏
        3.截屏
        UIGraphicsBeginImageContextWithOptions(containerView.bounds.size, YES, containerView.window.screen.scale);
        [xxx drawViewHierarchyInRect:containerView.bounds afterScreenUpdates:NO];
        
        // 加一层动画的View,这里会有layer一个个铺在上面,是原始切割数量的两倍,正面是from,背面是to,事先摆好位置
        4.[containerView addSubview:transitionContainerView];
        
        5.计算二位数组切割后
        CGFloat sliceSize = round(CGRectGetWidth(containerView.bounds) / 8.f);
        NSUInteger xSlices = ceil(CGRectGetWidth(containerView.bounds) / sliceSize);
        NSUInteger ySlices = ceil(CGRectGetHeight(containerView.bounds) / sliceSize);
        
        // 防止layer,layer是加到小格子View上面的,但是layer是全屏的,所以每个小格子要对应上必须进行负数偏移,不然图像都不完整了
        6.布局
        for (NSUInteger y = 0 ; y < ySlices; y++)
        {
            for (NSUInteger x = 0; x < xSlices; x++)
            {
                CALayer1
                CALayer2
                
                UIView *toCheckboardSquareView
                [toCheckboardSquareView.layer addSublayer:toContentLayer];
                
                UIView *fromCheckboardSquareView
                [fromCheckboardSquareView.layer addSublayer:fromContentLayer];
    
                [transitionContainerView addSubview:toCheckboardSquareView];
                [transitionContainerView addSubview:fromCheckboardSquareView];
            }
        }
        // 上面是to和from的View交错放置,所以这个时候需要*2来拿出各自的View
        __block NSUInteger sliceAnimationsPending = 0;
        for (NSUInteger y = 0 ; y < ySlices; y++)
        {
            for (NSUInteger x = 0; x < xSlices; x++)
            {
                7.计算时间........
                // 通过上面定的时间计算持续时间以及延迟时间
                NSTimeInterval startTime = projectionLength/(transitionVectorLength + transitionSpacing) * transitionDuration;
                NSTimeInterval duration = ( (projectionLength + transitionSpacing)/(transitionVectorLength + transitionSpacing) * transitionDuration ) - startTime;
                sliceAnimationsPending++;
                [UIView animateWithDuration:duration delay:startTime options:0 animations:^{
                    8.开始动画。。。。。。
                } completion:^(BOOL finished) {
                    // Finish the transition once the final animation completes.
                    if (--sliceAnimationsPending == 0)
                        9. 结束动画。。。。。。
        }
    }


    总结下:

    1.present和push动画是有所区别的,结构可以看上面的图,有的时候不区分是会出问题

    2.自定义无论哪种,第一步就是实现该容易控制器代理的方法返回自定义动画组件(该组件必须实现指定代理)

    第二步就是实现自定义动画控制器

    3.CAEmitterLayer可以实现很多离子特效,这里简单介绍了两个

    这个只是非常简单的两步走实现自定义转场动画,先有个基本了解,在进行更高层次的自定义效果就会更好,这些动画对性能来讲肯定会有所影响,有这样的想法必然就回去用GPUImage和OpenGL来实现图形动画,这些实现的效果等以后有空了在去研究分析下

    简单的介绍了下流程,反正我看东西还是喜欢看Demo,需要的同学点下面的链接直接下载看吧

    文章Demo链接:点击打开本文Demo链接

    参考唐巧大神的理论知识文章:点击打开链接






    展开全文
1
收藏数 2
精华内容 0
关键字:

dissmiss后变短 ios