1.正确设置Lable圆角的姿势
需求如图(常用作标签):
常规做法:
self.label.text = @"皮尔斯";
self.label.backgroundColor = [UIColor brownColor];
self.label.layer.cornerRadius = 5;
self.label.layer.borderWidth = 1;
self.label.layer.borderColor = [UIColor cyanColor].CGColor;
self.label.layer.masksToBounds = YES;
我这里用模拟器调试如图:
标黄的地方是告诉我们这些地方引起了离屏渲染
(更新于2019年2月27日01:03:11)
离屏渲染简单概念:GPU在当前屏幕缓冲区之外开辟一个新的缓冲区进行渲染操作,产生额外开销,可能会造成卡顿
我们知道当FPS小于60的时候,我们肉眼会感到卡顿
FPS即每秒刷新数,即 1000 / 60 ≈ 16.7ms,即16.7ms以内刷新一次页面就不会感到卡顿,系统生成图像信号是靠 CPU + GPU 共同工作的,即CPU + GPU 共同工作生成图像需要 < 16.7ms,而如果CPU或者GPU工作压力太大,生成图像信号大于这个时间,那么就会放弃掉这一帧,而继续显示之前的图像
因为离屏渲染会增加GPU的压力,所以我们应该尽量避免离屏渲染的发生
现在修改一下代码
self.label.text = @"皮尔斯";
self.label.layer.backgroundColor = [UIColor brownColor].CGColor;
self.label.layer.cornerRadius = 5;
self.label.layer.borderWidth = 1;
self.label.layer.borderColor = [UIColor cyanColor].CGColor;
效果如图:
哈哈,离屏渲染没有了!
精髓在于我们干掉了masksToBounds这行代码,而颜色的设置放到了layer层
以后碰到类似需求就这样做吧,思密达!
2.数组之泛型数组
Person* p1 = [Person new];
Person* p2 = [Person new];
Person* p3 = [Person new];
NSArray* arr = @[p1,p2,p3];
for (int i = 0; i < arr.count; i++) {
arr[0];
}
如图arr数组里存储了3个Person实例,并进行遍历
这样写固然没有问题,但是我数组的初始化如果不是用字面量的方式,arr里元素到底存储了那些东西,我们是需要扒代码的,有些项目的代码复杂度远远超乎你的想象,此时是非常耗时间的
OC的数组是可以存储任何类型对象的,但是我强烈建议用泛型除非特殊需求(虽然我接过这样的需求)
代码改动下:
Person* p1 = [Person new];
Person* p2 = [Person new];
Person* p3 = [Person new];
NSArray<Person*>* arr = @[p1,p2,p3];
为什么建议用泛型呢?
1.在数组声明的时候就已经明确数组里元素的数据类型了
2.用enumerateObjectsUsingBlock遍历数组时,你会发现数组里元素类型IDE已经帮我们输入好了(超赞的)而且《52高效》的书推荐我们用这种方式遍历数组
3. ARC下如何打印retainCount(引用计数)
// obj目标对象
NSInteger retainCount = CFGetRetainCount((__bridge CFTypeRef)chen);
NSLog(@"Retain count is %ld", retainCount);
4.category你是否这么用过?
之前在某项目看到这样的分类:
@interface NSString (Help)
- (BOOL)isEmpty;
@end
@implementation NSString (Help)
- (BOOL)isEmpty {
if (self == nil) {
return YES;
}
return NO;
}
@end
一个判断字符串是否为空的分类,按照代码逻辑当字符串对象为nil的时候,认为为空返回true
但是却犯了一个大问题:当字符串对象为nil的时候,isEmpty方法是永远不会执行的,逻辑上表现为一个为nil的字符串对象他不认为是空的,返回false(这样做逻辑不就中奖了么?)
为什么会这样呢?
当字符串对象为nil的时候即[nil isEmpty],我们向nil对象发送了一条消息,OC的机制向nil发送消息是允许的,但是方法永远不会执行,这样做逻辑你说会不会中奖?
5.将view 放到的图层最上端
// 目标view假设为topView
// 1
[self.view insertSubview:topView atIndex:[self.view subviews].count];
// 2
[[topView superview] bringSubviewToFront:topView];
6.UI妹子眼中一根线的粗细到底是多少?
#define SINGLE_LINE_HEIGHT (1 / [UIScreen mainScreen].scale)
为什么要这样呢:
scale的官方解释:
中文:
与屏幕相关的自然比例因子。
此值反映从默认逻辑坐标空间转换到此屏幕的设备坐标空间所需的缩放因子。 使用点测量默认逻辑坐标空间。 对于标准分辨率显示器,比例因子为1.0,一点等于一个像素。 对于Retina显示器,比例因子为2.0,一个点由四个像素表示。
7.这个细节你是否留意到了?
直接上图(以某大厂出的app举例)
这种控件现在越来越多的项目在用,但是呢,这个细腻的地方在于:
滑到“全部”这个页面的时候,再次右滑是可以pop的,虽说看起来一样的控件,但是我发现很多app是没有处理这个滑动pop逻辑的
我们自己的项目中也大面积使用了这种方式,当然这种细腻的体验我当然是要加进来的(o)/
直接上代码(如果有更好的思路希望提出来,共同学习哈!)
假设如图例子的UI结构是:ScrollView里添加了5个子View
// 给VC的view添加pan手势
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] init];
panGesture.delegate = self;
[self.view addGestureRecognizer:panGesture];
// 实现此代理
// 询问一个手势接收者是否应该开始解释执行一个触摸接收事件
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 这个_pageIndex就是记录当前滑到了哪个title下
// 比如说在这里_pageIndex == 0 就是“全部”这个title下的页面
if (_pageIndex == 0) {
CGPoint translatedPoint = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:self.view];
NSLog(@"%f %f",translatedPoint.x,translatedPoint.y);
// 当在“全部”title下,且右滑的情况下,禁止scrollView滚动
self.scrollView.scrollEnabled = translatedPoint.x < 0;
}
return NO;
}
8.这个细节你是否留意到了?
直接上图
这种相册预览相信大家已经见过太多了,但是请注意个小细节,图片是由模糊渐渐变清晰的(微信图片浏览器就有这个细节)
这么做好处在哪里呢?
I/O操作是比较号资源的,我们先拿小图即缩略图展示出来,提高展示效率,其次获取高清图之后再替换,既提高了效率又加强了交互体验,一箭双雕,nice。
如果有更好的实现方式,请留言或者联系我
代码的实现方式请参考我的dolin_demo
以前碰到的都忘记总结了,就想起了这些,不过后续会持续更新
如果给你带来了一点点帮助,就点个赞吧😆