目录:
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.通知顺序:一定要先监听,在发出2.一定要移除
bug:监听不到通知,马上想到有可能先发出通知,在监听通知
通知多线程使用
- 异步线程,不能监听到通知
- 异步任务,执行顺序不确定
下面代码验证:异步线程可以监听通知
- (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. 总结:监听通知代码 由发布通知线程决定