iOS-部分知识点小结

作者: 麦穗0615 | 来源:发表于2016-07-30 20:00 被阅读442次

    目录:
    1.block的基本使用
    2.ScrollView的底层实现
    3.Bounds和Frame简介
    4.assign和weak的区别
    5.枚举中的位运算
    6.Size和Center
    7.通知的补充
    8.通知多线程使用

    block的基本使用

    • 1.block声明
      block声明: 返回值(^block变量名)(参数)
      #void(^block)() --->无参无返回值
    • 2.block定义:三种方式 =^(参数){}
      // 第一种
      void(^block1)() = ^{ };
      // 第二种 如果没有参数,参数可以隐藏,如果有参数,定义的时候必须写参数,而且必须要有参数变量名
      void(^block2)(int) = ^(int = a){ };
      // 第三种 block返回可以省略,不管有没有返回值,都可以省略
      int(^block3)() = ^int{
      return 3;
      };
    • 3.block类型
      // block类型: int(^)(NSString *)
      int(^block4)(NSString *) = ^(NSString *name){
      return 2;
      };
    • 4.block调用
      block1();
    • 5.block快捷方式
      inlineBlock - c Inline Block as Variable

    ScrollView的底层实现

    • 思路分析:
      1.scrollView上下滚动时scrollView没有滚动,是上面的内容在滚动,通过该bounds实现滚动,
      用代理方法去验证,设置代理,遵守协议,在crollViewDidScroll:(UIScrollView *)scrollView打印
      NSLog(@"%@",NSStringFromCGRect(scrollView.bounds));,验证结果显示,bounds的y值一直在变化,
      其实就是偏移量,向上移动时,y值增加,向下移动时,y值减少。在打印NSLog(@"%@",NSStringFromCGPoint(scrollView.contentOffset));
      进行对比,验证表明,偏移量就是从bounds中取的的。
      2.当我们手指网上拖时,内容往上走,y值是+,可视范围往下走。
      3.通过,点击UIScrollView查看底层,我们知道了scrollView要想滚动,是因为加上了两个手势,一个Pan,一个捏合手势。
    • 思路演示
      模仿系统控件 ==>怎么去用 ==> 滚动scrollView其本质是在滚动内容 ==>改bounds ==>验证
      ==>手指网上拖动,bounds y++ ,内容才会往上走
    • 代码片段①
      #import "ViewController.h"
      @interface ViewController ()<UIScrollViewDelegate>
    
       @end
    
      @implementation ViewController
    
       - (void)viewDidLoad {
          [super viewDidLoad];
       //   模仿系统控件 ==>怎么去用 ==> 滚动scrollView其本质是在滚动内容 ==>改bounds ==>验证
       //     ==>手指网上拖动,bounds y++ ,内容才会往上走
        UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
        scrollView.contentSize = CGSizeMake(0, 1000);   //  内容在滚content
        scrollView.delegate = self;
        [self.view addSubview:scrollView];
    
        UISwitch *switchView = [[UISwitch alloc]init];
        [scrollView addSubview:switchView];
         }
        #pragma mark - UIScrollViewDelegate
      - (void)scrollViewDidScroll:(UIScrollView *)scrollView
      {
        NSLog(@"%@",NSStringFromCGRect(scrollView.bounds));
        NSLog(@"%@",NSStringFromCGPoint(scrollView.contentOffset));
    
      }
    
    • 用UIView模仿ScrollView
      #import "ViewController.h"
      @interface ViewController ()<UIScrollViewDelegate>
    
      @property(strong,nonatomic)UIView *scrollView;
      @end
    
      @implementation ViewController
    
        - (void)viewDidLoad {
          [super viewDidLoad];
          UIView *scrollView = [[UIView alloc]initWithFrame:self.view.bounds];
          [self.view addSubview:scrollView];
          _scrollView = scrollView;
          //  要想移动--添加手势
          //  1.添加Pan手势
          UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
          [scrollView addGestureRecognizer:pan];
          UISwitch *switchView = [[UISwitch alloc]init];
          [scrollView addSubview:switchView];
      }
      //  pan手势
      - (void)pan:(UIPanGestureRecognizer *)pan
      {
          /*  每次拖动的时候,都会改动bounds,但是我们应该指导你拖      动了多少
           当往上拖时, NSLog(@"%@",NSStringFromCGPoint(transP));,经过打印
           y是负的,按照正常来说y,网上拖应该是正的。这时候我们就要取反。继而
           bounds.origin.y -= transP.y;但是每次减transP.y,也会出现问题,使scrollView会
           滚的很远。所以要做个复位。
           */
    >
           //   1. 获取手指的偏移量是多少---参数:手指在哪个View上的点
              CGPoint transP =  [pan translationInView:pan.view];
             NSLog(@"%@",NSStringFromCGPoint(transP));
            //  2.修改bounds
             CGRect bounds = _scrollView.bounds;
             bounds.origin.y -= transP.y;
           _scrollView.bounds = bounds;
            //  3.复位
          [pan setTranslation:CGPointZero inView:pan.view];
      }
    

    Bounds和Frame简介

    • Frame:以父控件左上角为原点
    • Bounds:以自己的左上角为原点,boundsx,y永远为0,这个是错误的
      1.当我们修改某控件bounds的x,y坐标时,对于自己的位置是不会发生变化的。但是对,自己内部的子控件,还是有影响的。
      (说明了bounds的x,y是可以加减的,并不是永远都为0。x,y坐标的改变,只针对于自己的子控件。)
    • frame和bounds都是用来描述一块区域
      frame:描述的可视范围
      bounds:可视范围,在内容的区域。
      所有的子控件都是相对于内容的。
      bounds:本质是修改了内容的原点。
      相对性:
      可视范围相对于父控件的位置永远不变
      可视范围相对于内容,位置改变

    assign和weak的区别

    • 解释weak,assgin什莫时候使用weak和assgin
      weak: (__weak修饰)弱指针,不会让引用计数器+1,如果指向的对象被销毁,指针会自动清空。
      ARC: 才有weak,这个东西。
      MRC: 没有weak
      assgin:(_unsafe_unretained修饰),不会让引用计数器+1,如果指向的对象被销毁,指针不会清空。会造成僵尸对象现象。

    枚举中的位运算

    只要枚举中,有位运算就可以使用并运算 |

    • 为什莫?
      代码:如一个方法监听了两个事件,编辑时,和值改变时。
      //1 << n,2^n 左移
      int a = 1 << 0; // 1
      int b = 1 << 1; // 2 #①
      int c = 1 << 2; // 4
      int d = 1 << 3; // 8
          - (void)viewDidLoad {
               [super viewDidLoad];
            [_textField addTagrget:self action:@selector(textBegin) forControlEvents: UIConrtolEventEditingDidBegin | UIControlEventEditingChanged]
     >        
              [self test:a | b];         #②把位运算传进去
             }
              >
              - (void)textBegin{
                NSLog(@"开始编辑的时候会调用");
             }
    
          - (void)test: (int)value{
             //  解析:value,判断下是否包含a,b,c,d
             // &解析有没有包含a,b, c,d
             //   NSLog(@"%d %d %d %d",value & a,value & b,value & c,value & d};
               if (value & a)NSLog(@"包含了a");
               if (value & b)NSLog(@"包含了b");
               if (value & c)NSLog(@"包含了c");     #③ 解析
               if (value & d)NSLog(@"包含了d");
            }
    
    打印结果

    如图:


    左移计算

    [里面去做判断===》forControlEvents]

    Size和Center

    • 先设置尺寸在设置center,否则控件控件的位置会不准确
      - 用frame设置时,先设置center,后设置size,会导致控件位置不准确,跑偏
      - 用bounds,没事
      # 推荐:先设置size在设置center
    • 原因:(如图)
      frame是从左上角,控件向下扩展
      bounds是从中心点慢慢扩大


      frame
    • 建议:
      如果size,从frame取出来,先设置size,在设置center
      如果size,是从bounds取出来,就不用考虑center和size的区别

    通知的补充

    • 通知(要学习的点):
      1.如何发出通知
      2.监听通知
      3.通知注意点
    • 代码
      (方式一)
      - (void)viewDidLoad{
      [super viewDidLoad];
      // 1.发出通知
      // Name:通知名称
      // object:谁发出的通知
      [[NSNotificationCenter defaultCenter] postNotificationName: @"note" object:nil]; // 匿名发送
            // 2.监听通知
             //    addObserver:谁监听
             //    selector: 只要一监听到通知,就会调用观察者这个方法
             //   Name:通知名称
             //   object:谁发出的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveNote) name:@"note" object:nil];
       }
     >
           - (void)reciveNote{
    
          NSLog(@"接受到通知");
    
      }
         //  一个对象即将销毁的时候就会调用
         - (void)dealloc{
            //   3.移除通知
             [[NSNotificationCenter defaultCenter] removeObserver:self];
         }
                                     方式二
             //  监听通知
             /**
                Name:通知名称
                object:谁发出的通知
                queue:队列
                usingBlock:只要监听到通知,就会调用block
               */  
             @property(nonatomic ,weak) id observe;
    
            id observe =  [[NSNotificationCenter defaultCenter] addObserverForName:@"note"  object:nil 
               queue:nil   usingBlock:^(NSNotification * _Nonull note){
                 //  只要监听到通知,就会调用block
                 NSLog(@"%@",[NSThread currentThread]);
                 NSLog(@"%@",self);
               ]};
           系统观察,怎么去移除
       - (void)dealloc{ 
           // 3.移除通知
             [[NSNotificationCenter defaultCenter] removeObserver:_observe];
            }
    

    上面一定监听不到通知,2要跟1调换顺序,先监听通知,发出通知。

    • 注意点
      1.通知顺序:一定要先监听,在发出
      bug:监听不到通知,马上想到有可能先发出通知,在监听通知
      2.一定要移除

    通知多线程使用

    • 异步线程,不能监听到通知
    • 异步任务,执行顺序不确定
    • 下面代码验证:异步线程可以监听通知
      - (void)viewDidLoad{
      [super viewDidLoad];
       // 2.监听通知
             //    addObserver:谁监听
             //    selector: 只要一监听到通知,就会调用观察者这个方法
             //   Name:通知名称
             //   object:谁发出的通知
       dispatch_async(dispatch_get_global_queue(0,0),^{
            //  异步任务
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveNote) name:@"note" object:nil];
       };       
      
      }
    
           - (void)touchesBegan:(NSSet<UITouch *>*)touches withEvent:(UIEvent *)event{
    
           //   1.发出通知
           //   Name:通知名称
           //   object:谁发出的通知
           [[NSNotificationCenter defaultCenter] postNotificationName: @"note" object:nil];  //  匿名发送  
         }
            //  监听到通知就会调用
            //  异步:监听通知  主线程:发出通知  接受通知代码在主线程
             //  在接受通知代码中,可以加上主队列任务
             // 总结:监听通知代码  由发布通知线程决定
           - (void)reciveNote{
    
          NSLog(@"接受到通知");
    
          dispatch_sync(dispatch_get_main_queue(),^{
           //  更新UI
       });
      }
         //  一个对象即将销毁的时候就会调用
         - (void)dealloc{
            //   3.移除通知
             [[NSNotificationCenter defaultCenter] removeObserver:self];
         }
    
    • 总结:
      1. 异步:监听通知 主线程:发出通知 接受通知代码在主线程
      2. 在接受通知代码中,可以加上主队列任务
      3. 总结:监听通知代码 由发布通知线程决定

    相关文章

      网友评论

      • 豆小兽:写的并不那么通俗易懂,有些地方有点晕~
      • code_间特门:分析的到位,想必这位兄台也是有好几年的开发经验了。 :grin:

      本文标题:iOS-部分知识点小结

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