「 iOS 知识小集 」2018 · 第 23 期
上周公众号发布的以下文章:
本期知识小集的主要内容包括:
- 用 NSDecimalNumber 处理 iOS 中的货币金额
- 如何更容易看懂宏
- Storyboard/Xib 颜色空间的坑
- VC 多层 push 后回到指定页面的几种方法
- 添加沙箱技术测试员报错的问题
- UIViewController 设置导航栏和标签栏不同 title 的问题
- 苹果官方类库中 NSDateFormatter 的小 bug
用 NSDecimalNumber 处理 iOS 中的货币金额
作者: halohily
在iOS开发中,经常遇到货币金额的表示与计算,你可能会使用 double 或 float 这样的浮点数,也可能使用 NSString 。无论用哪个,都需要再编写繁琐的精度控制、小数位数控制等代码。其实,苹果为我们提供了一个标准类 NSDecimalNumber
来处理这样的需求。
NSDecimalNumber 是 NSNumber 的子类,它提供了完善的初始化方法。对于令人头疼的金额计算,它还提供了贴心的加、减、乘、除运算方法。在进行这些运算的时候,你还可以通过 NSDecimalNumberHandler 对象来对运算的处理策略进行设置,比如舍入模式的选择,数据溢出、除零等异常情况的处理等。
下次遇到货币金额的需求,不妨了解一下 NSDecimalNumber。
参考资料:
- iOS 数字精准计算之NSDecimalNumber
https://www.jianshu.com/p/ea4da259a062
- NSDecimalNumber数字精确
https://www.jianshu.com/p/25d24a184016
如何更容易看懂宏
作者: Lefe_x
相信你和我一样,也遇到过特别难理解的宏定义,比如宏与宏之间嵌套、带参数的宏。我们看个例子(这个宏并不是特别难,但也很绕):
#define JPBOXING_GEN(_name, _prop, _type) \
+ (instancetype)_name:(_type)obj \
{ \
JPBoxing *boxing = [[JPBoxing alloc] init]; \
boxing._prop = obj; \
return boxing; \
}
JPBOXING_GEN(boxObj, obj, id)
这个例子看着总是怪怪的,如果把上面的宏转换成实际代码,相信你会很容易看懂。
+ (instancetype)boxObj:(id)obj
{
JPBoxing *boxing = [[JPBoxing alloc] init];
boxing.obj = obj;
return boxing;
}
其实就是各种参数的替换导致阅读起来比较困难。我们都知道程序经过预处理后就会把宏转换为实际的代码,而 Xcode 为我们提供了对单个文件进行预处理(Produce -> Perform Action -> Preprocess 'xxxx.m'),这样处理后,上面的宏就变成了:
+ (instancetype)boxObj:(id)obj {
JPBoxing *boxing = [[JPBoxing alloc] init];
boxing.obj = obj;
return boxing;
}
经过预处理后和我们手动翻译的结果一样。
Storyboard/Xib 颜色空间的坑
作者: Vong_HUST
今天分享一下 Xcode Interface Builder
设置背景色的一个坑。从 Xcode8
起,Xib/Storyboard
里的颜色空间默认从 Generic RGB
换成了 sRGB
,但又不是所有的都会转换,很奇怪。所以当时在适配 Xcode8
的时候,颜色空间都统一全局替换了一遍。最近又遇到一次这个坑,在 Storyboard
把某个视图背景色从白色更改为 0xf0f1f2
,然后 run 起来,和其 superview
(superview
的背景色是用代码设置的 0xf0f1f2
)竟然有一个明显的分割线,所以回想起当时适配时的这个问题,然后取到 Storyboard
里面一看,果然是颜色空间被莫名改为了 Generic RGB
,如图所示。所以手动改变其颜色空间为 sRGB
即可。
参考链接
- Xcode Interface Builder 指定顏色與實際有出入
http://t.cn/RgpFOPg
- WWDC Working with Wide Color
http://t.cn/ReADdu7
VC 多层 push 后回到指定页面的几种方法
作者: 这个汤圆没有馅
场景如下: RootVC -- > A -- > B -- > C,然后现在要求C直接pop回到A。
方法一:C返回到B的时候写个回调,B接收到回调再自己pop到A,但是这个方法B的页面会闪现一下,用户体验不好,不推荐。
方法二:在B push 到C的时候,直接把B从导航控制器的堆栈中移除,如图一。
方法三:写一个UIViewController的catrgory,方法实现如图二。在C的backAct方法中使用,如图三。有的同学可能会怀疑B会不会内存泄露,可以在B中打印dealloc。
这里比较推荐方法三。不论有多少级的push,只要传入指定页面的类名,都能回到该页面。
添加沙箱技术测试员报错的问题
作者: 高老师很忙
在测试 IAP 的时候需要添加沙箱技术测试员,相当于创建一个虚拟的 AppleID,填写的邮箱是不能写真实 AppleID 邮箱的,要不然就会报错,可以随意写一个不存在的邮箱,为了方便,创建一个简短的密码就会报错误:
按照提示改好后,依然报错:
并且没有任何的提示,感觉这点好坑,尝试了N遍之后发现是密码的复杂度不够,要包含大小写和数字,虽然是虚拟的 AppleID,但是密码规则要和正式的 AppleID 一样,希望以后苹果把错误提示做的更好吧!😂
UIViewController 设置导航栏和标签栏不同 title 的问题
作者: KANGZUBIN
我们通常会在一个 UIViewController
的 viewDidLoad
方法中通过 self.title = xxx
的方式给一个页面设置其导航栏标题,相信大家对这再熟悉不过了。
如果一个 VC 页面中同时具有 NavigationBar
(导航栏)和 TabBar
(标签栏),而且我们又想让这两个地方的标题显示不一致,如下图所示,在首页顶部导航栏标题中显示“知识小集”,而在底部标签栏标题中显示“首页”:
但是,当我们在 UITabBarController
中初始化好上述页面结构后,且设置首页 VC 的 tabBarItem.title
为 “首页”,然后在首页 VC 的 viewDidLoad
方法中设置 self.title
为 “知识小集”,编译运行后我们发现首页底部标签栏的标题也变成“知识小集”了,而不是刚设置的“首页”。
查了苹果文档中关于 UIViewController
中 title
属性的定义,有如下一段描述:
If the view controller has a valid navigation item or tab-bar item, assigning a value to this property updates the title text of those objects.
也就是说,如果一个 VC 同时有导航栏和标签栏,那么当给 title
赋值时,会同时修改这两个地方的标题。所以如果我们只想设置导航栏的标题,可以通过 self.navigationItem.title = xxx
的方式来实现。
因此,在一个 VC 中设置相关标题简单总结如下:
-
self.navigationItem.title: 设置 VC 顶部导航栏的标题
-
self.tabBarItem.title: 设置 VC 底部标签栏的标题
-
self.title: 同时修改上述两处的标题
参考文档
- UIViewController.title
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621364-title?language=objc
苹果官方类库中 NSDateFormatter 的小 bug
作者: 我是乔忘记疯狂
不知道有多少人和我一样是今天才知道这个问题的
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.dateFromString("1987-04-12") // nil
这个问题在 StackOverflow 上是有人提过的。其实主要跟一些国家实行 夏时制(Daylight saving time)
有关系,尤其是美国
解决办法我是尝试这样增加一句代码
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
let date = formatter.dateFromString("1987-04-12") // Apr 12, 1987, 1:00 AM
最后推荐一个夏时制的相关阅读,高晓松的 鱼羊野史 第1卷 中1月6日那一章,有讲到美国于1974年1月6日开始实行夏时制并一直到今天,还讲到其他一些相关的有意思的事情。
参考文档
- NSDateFormatter.dateFromString returns nil for specific dates in specific languages
https://stackoverflow.com/questions/32408898/nsdateformatter-datefromstring-returns-nil-for-specific-dates-in-specific-langua
关注我们
欢迎关注我们的公众号:iOS-Tips,也欢迎加入我们的群组讨论问题。可以公众号留言 ios
、flutter
、web
、pwa
、小程序
等关键词获取入群方式。