Daniel's Code Home

写代码就是一场修行


  • 首页

  • 归档

  • 分类

  • 标签

  • TopX

  • 关于

Tips13-collectionView调用reloadData刷新数据时造成闪屏

发表于 2019-03-08 | | 阅读次数:
| 字数统计: 89

昨天,测试给我提了一个bug:xx列表页刷新时有闪屏。自己试着下拉刷新了一下,确实存在这种问题,猜测是reloadData时有相关动画造成的,于是尝试在relodData时关闭动画效果。

1
2
3
[CATransaction setDisableActions:YES];
[self.collectionView reloadData];
[CATransaction commit];

再次下拉刷新,闪屏已经消失.

Tips12-下拉刷新或上拉加载时UIButton更换图片或文字闪动问题的解决方案

发表于 2018-11-25 | | 阅读次数:
| 字数统计: 193

项目里有一个控件是左图标右文字,所以很自然地选用了UIButton来实现。在完成了下拉和上拉功能后,发现在刷新数据源后,UIButton中的图片和文字会有瞬间闪动。在Google了一下后,发现了问题解决方案。其实代码很简单,仅仅需要一行即可:

1
self.button.titleLabel.text = string;

是的,仅仅需要一行即可,但是并不是把这行代码添加在任何位置都有效果,该行代码只有添加在一个地方才有效果,即:

1
2
self.button.titleLabel.text = string;
[self.button setTitle:string forState:UIControlStateNormal];

同样的,解决图片闪动的方法类似,只需要这样:

1
2
self.button.imageView.image = image;
[self.button setImage:image forState:UIControlStateNormal];

Tips11-解决JSON解析导致数值精度丢失的问题

发表于 2018-07-16 | | 阅读次数:
| 字数统计: 196

周五的时候QA测出一个取现操作失败的bug,跟踪了数据走向,发现是由于double类型的数值在转换成JSON字符串的时候精度丢失导致的。

解决方案:使用iOS中的专门用来处理精度的对象NSDecimalNumber

1
2
3
NSString *doubleString = [NSString stringWithFormat:@"%lf", num];
NSDecimalNumber *decNumber = [NSDecimalNumber decimalNumberWithString:doubleString];
NSString *decimalStr = [decNumber stringValue];

结合到自身项目中,因为这个“钱”是从服务器请求过来,到最后又传回给服务器的,在这个过程中值不会变,所以,可以在拿到服务器的返回值时,先将“钱”利用上述代码转成NSString类型,这样在模型转JSON字符串的时候就不会有double到NSString的转换,从而也避免了精度丢失的问题。

Tips10-修改UITextField的placeholder字体

发表于 2018-07-05 | | 阅读次数:
| 字数统计: 193

我经常使用的修改UITextField的placeholder字体方法有两种:

KVC

1
2
3
yourTextField.placeholder = @"username is here";
[yourTextField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[yourTextField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];

设置AttributedPlaceholder

1
2
NSDictionary *attributed = @{NSFontAttributeName: [UIFont boldSystemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]};
youTextFiled.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"username is in here!" attributes:attributed];

我个人推荐使用Attributed的方式来设置,因为KVC不知道什么时候会失效,而且适用范围比较小。
有时候,当字体过小的时候,placeholder的字体会显示不是垂直居中的,这需要用到NSParagraphStyle,而用KVC是没法解决的。

我的解决办法是:

1
2
3
NSMutableParagraphStyle *style = [yourTextField.defaultTextAttributes[NSParagraphStyleAttributeName] mutableCopy];
style.minimumLineHeight = yourTextField.font.lineHeight - (yourTextField.font.lineHeight - [UIFont systemFontOfSize:14.0].lineHeight) / 2.0;
yourTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"username is in here!" attributes:@{NSForegroundColorAttributeName: [UIColor redColor], NSFontAttributeName: [UIFont systemFontOfSize:14.0], NSParagraphStyleAttributeName: style}];

Tips9-如何在Swift中调用OC的单例类方法

发表于 2018-06-23 | | 阅读次数:
| 字数统计: 201

现在Swift越来越被开发者所喜爱,用到的地方也越多,但是不可否认OC也有其特殊的「魔力」,所以有时候需要在Swift中调用OC的类或方法。调用并不难,利用桥接即可解决,但是有时候会碰到让人摸不着头脑的问题。

OC中的单例类方法 + (instancetype)manager 在Swift中会被忽略

所以在OC中 [SchoolManager manager]这样可以调用的方法,在Swift中使用SchoolManager.manager是无效的。

原因就是Xcode限制了Swift对OC初始化相关方法的调用。

解决方案

使用Xcode认可的关键字default,singleton,shared当前缀来声明OC的单例方法名。

1
2
3
+ (instancetype)defaultManager;
+ (instancetype)singletonManager;
+ (instancetype)sharedManager;

这样在Swift中可以使用.default, .singleton, .shared来生成相关单例。

Tips8-iOS中如何设置只读属性

发表于 2018-06-15 | | 阅读次数:
| 字数统计: 114

在项目中经常需要创建这样一种变量,它对内是可读写的,但是对外是只读的。在OC中的实现很方便,只要在.h文件中将属性定义为readonly,在.m文件中将该属性重新定义为readwrite即可。

1
2
3
4
5
.h
@property (nonatomic, copy, readonly) NSString *name;

.m
@property (nonatomic, copy, readwrite) NSString *name;

那么在Swift中如何定义这样的变量呢?代码如下:

1
private(set) var name : String!

Tips7-iOS中隐藏StatusBar而不会改变导航栏高度的方法

发表于 2018-06-08 | | 阅读次数:
| 字数统计: 333

在开发的过程中,可能会遇到隐藏statusBar的需求。通常的做法就是在需要隐藏状态栏的ViewController中添加以下代码:

1
2
3
- (BOOL)prefersStatusBarHidden {
return YES;
}

我们打开App,美滋滋地看效果,咦?为什么导航栏少了20px?而且每次进入或离开这个Controller的时候,导航栏有明显的位移,这太影响观感了。设计妹子那肯定不能通过。那有没有其他方法设置状态栏的隐藏呢? 有!
For Example:

Objective-c 写法

可以在需要隐藏状态栏的ViewController的[viewWillAppear:]方法里添加代码

1
[UIApplication sharedApplication].keyWindow.windowLevel = UIWindowLevelStatusBar + 1;

在[viewWillDisappear:]方法里添加:

1
[UIApplication sharedApplication].keyWindow.windowLevel = UIWindowLevelNormal;

Swift 写法

1
UIApplication.shared.keyWindow?.windowLevel = UIWindowLevelStatusBar + 1
1
UIApplication.shared.keyWindow?.windowLevel = UIWindowLevelNormal

运行App,打开该ViewController,可以发现状态栏被完美隐藏。

原因

为什么改变了keyWindow的windowLevel,就能隐藏状态栏呢?
因为statusBar也有自己的UIWindow,它的windowLevel就是UIWindowLevelStatusBar,高于UIWindowLevelNormal,所以会优先显示statusBar,当我们改变了keyWindow 的windowLevel之后,statusBar的显示优先级没有navigationBar的高了,而navigationBar又是不透明的,所以我们看不到它背后的statusBar,就达到了隐藏状态栏的效果。而只要statusBar不是隐藏状态,整个导航栏的高度就不会改变。

Tips6-快速定位错误提示「NaN」

发表于 2018-06-07 | | 阅读次数:
| 字数统计: 179
NaN,是Not a Number的缩写,用于处理计算中出现的错误情况

前两天查看了app的友盟错误统计,发现有很多NaN的错误。Google了一下NaN的含义,NaN是Not a Number的缩写,用于处理计算中出现的错误情况。简单来说,就是出现这个错误的地方可能包含了异常值。

1.一般和Layer相关的,可能是重复设值、刷新和释放的问题;

2.CGRectMake设置宽高时出现了问题,有可能出现了除以0的操作

顺着这个思路,定位了友盟的bug,发现错误基本出现在有除法的地方,所以可以肯定是发生了除以0的操作,对除数是0的情况进行保护即可。

Tips5-比较两张图片是否相同

发表于 2018-06-06 | | 阅读次数:
| 字数统计: 194

在开发过程中,可能会碰到需要比较两张图片是否相同的情景。这时,需要分两种情况讨论:

两张图已经加载到resource中

如果两张图片都已经加载到resource中,并且图片名称已知,那么使用[UIImage imageNamed:]方法创建2个UIImage对象,然后用isEqual比较。

1
2
3
4
5
UIImage *imageA = [UIImage imageNamed:@"ImageA"];
UIImage *imageB = [UIImage imageNamed:@"ImageB"];
if ([imageA isEqual:imageB]) {
NSLog(@"isEqual");
}

两张图片存储在沙盒的某个位置

如果两张图片存储在iOS沙盒的某个位置,没有被加载到resource中,可以通过比较两个UIImage的data是否相同。

1
2
3
4
5
6
7
UIImage *imageA = [UIImage imageWithContentsOfFile:fileA];
UIImage *imageB = [UIImage imageWithContentsOfFile:fileB];
NSData *dataA = UIImagePNGRepresentation(imageA);
NSData *dataB = UIImagePNGRepresentation(imageB);
if ([dataA isEqual:dataB]) {
NSLog(@"isEqual");
}

Tips4-DisMiss Controller 到根控制器

发表于 2018-06-05 | | 阅读次数:
| 字数统计: 203
A控制器presentB控制器,B控制器presentC控制器,然后从C直接dismiss到A控制器

在项目中遇到过这种情况:A控制器presentB控制器,B控制器presentC控制器,然后C控制器需要直接dismiss到A控制器。
解决这个问题需要了解Controller的两个只读属性:presentedViewContrller和presentingViewController。它们所代表的含义是:被present的控制器和正在presenting的控制器。
For Example:

1
[A presentViewContrller:B animated: YES completion: nil];

对于控制器A和B,A相对于B来说就是正在presenting的控制器,B相对于A来说是presented的控制器,亦即, B.presentingViewContrller能拿到A控制器,A.presentedViewController能拿到B控制器。
了解了这两个概念后,我们怎么写从C控制器dismiss到A控制器呢?
我们可以在C控制器的返回方法里这么写:

1
2
3
4
5
UIViewController *rootVC = self.presentingViewController;
while (rootVC.presentingViewController) {
rootVC = rootVC.presentingViewController;
}
[rootVC dismissViewControllerAnimated:YES completion:nil];

12
QiuDaniel

QiuDaniel

13 日志
12 标签
GitHub
© 2018 — 2019 QiuDaniel