昨天,测试给我提了一个bug:xx列表页刷新时有闪屏。自己试着下拉刷新了一下,确实存在这种问题,猜测是reloadData时有相关动画造成的,于是尝试在relodData时关闭动画效果。
1 | [CATransaction setDisableActions:YES]; |
再次下拉刷新,闪屏已经消失.
写代码就是一场修行
昨天,测试给我提了一个bug:xx列表页刷新时有闪屏。自己试着下拉刷新了一下,确实存在这种问题,猜测是reloadData时有相关动画造成的,于是尝试在relodData时关闭动画效果。
1 | [CATransaction setDisableActions:YES]; |
再次下拉刷新,闪屏已经消失.
项目里有一个控件是左图标右文字,所以很自然地选用了UIButton来实现。在完成了下拉和上拉功能后,发现在刷新数据源后,UIButton中的图片和文字会有瞬间闪动。在Google了一下后,发现了问题解决方案。其实代码很简单,仅仅需要一行即可:1
self.button.titleLabel.text = string;
是的,仅仅需要一行即可,但是并不是把这行代码添加在任何位置都有效果,该行代码只有添加在一个地方才有效果,即:1
2self.button.titleLabel.text = string;
[self.button setTitle:string forState:UIControlStateNormal];
同样的,解决图片闪动的方法类似,只需要这样:1
2self.button.imageView.image = image;
[self.button setImage:image forState:UIControlStateNormal];
周五的时候QA测出一个取现操作失败的bug,跟踪了数据走向,发现是由于double类型的数值在转换成JSON字符串的时候精度丢失导致的。
1 | NSString *doubleString = [NSString stringWithFormat:@"%lf", num]; |
结合到自身项目中,因为这个“钱”是从服务器请求过来,到最后又传回给服务器的,在这个过程中值不会变,所以,可以在拿到服务器的返回值时,先将“钱”利用上述代码转成NSString类型,这样在模型转JSON字符串的时候就不会有double到NSString的转换,从而也避免了精度丢失的问题。
我经常使用的修改UITextField的placeholder字体方法有两种:
1 | yourTextField.placeholder = @"username is here"; |
1 | NSDictionary *attributed = @{NSFontAttributeName: [UIFont boldSystemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]}; |
我个人推荐使用Attributed的方式来设置,因为KVC不知道什么时候会失效,而且适用范围比较小。
有时候,当字体过小的时候,placeholder的字体会显示不是垂直居中的,这需要用到NSParagraphStyle,而用KVC是没法解决的。
我的解决办法是:1
2
3NSMutableParagraphStyle *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}];
现在Swift越来越被开发者所喜爱,用到的地方也越多,但是不可否认OC也有其特殊的「魔力」,所以有时候需要在Swift中调用OC的类或方法。调用并不难,利用桥接即可解决,但是有时候会碰到让人摸不着头脑的问题。
所以在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来生成相关单例。
在项目中经常需要创建这样一种变量,它对内是可读写的,但是对外是只读的。在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!
在开发的过程中,可能会遇到隐藏statusBar的需求。通常的做法就是在需要隐藏状态栏的ViewController中添加以下代码:1
2
3- (BOOL)prefersStatusBarHidden {
return YES;
}
我们打开App,美滋滋地看效果,咦?为什么导航栏少了20px?而且每次进入或离开这个Controller的时候,导航栏有明显的位移,这太影响观感了。设计妹子那肯定不能通过。那有没有其他方法设置状态栏的隐藏呢? 有!
For Example:
可以在需要隐藏状态栏的ViewController的[viewWillAppear:]方法里添加代码1
[UIApplication sharedApplication].keyWindow.windowLevel = UIWindowLevelStatusBar + 1;
在[viewWillDisappear:]方法里添加:1
[UIApplication sharedApplication].keyWindow.windowLevel = UIWindowLevelNormal;
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不是隐藏状态,整个导航栏的高度就不会改变。
在开发过程中,可能会碰到需要比较两张图片是否相同的情景。这时,需要分两种情况讨论:
如果两张图片都已经加载到resource中,并且图片名称已知,那么使用[UIImage imageNamed:]方法创建2个UIImage对象,然后用isEqual比较。1
2
3
4
5UIImage *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
7UIImage *imageA = [UIImage imageWithContentsOfFile:fileA];
UIImage *imageB = [UIImage imageWithContentsOfFile:fileB];
NSData *dataA = UIImagePNGRepresentation(imageA);
NSData *dataB = UIImagePNGRepresentation(imageB);
if ([dataA isEqual:dataB]) {
NSLog(@"isEqual");
}
在项目中遇到过这种情况: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
5UIViewController *rootVC = self.presentingViewController;
while (rootVC.presentingViewController) {
rootVC = rootVC.presentingViewController;
}
[rootVC dismissViewControllerAnimated:YES completion:nil];