一. 关于 info.plist 的国际化
info.plist 里面通常会添加【功能权限使用】相关的说明,因此 info.plist 也需要国际化。如何操作呢?
- 新建一个 .strings文件,命名为 InfoPlist.strings(文件名必须是这个!文件名必须是这个!文件名必须是这个!);
- 之后选中新建的 InfoPlist.strings 文件,点击右侧 Inspector 面板中的 Localize... ;
- 然后添加要支持的语言;
- 分别添加功能权限的 key 对应的文字说明 value,如下
NSCameraUsageDescription = "Take passport/ID card photos to upload";
NSPhotoLibraryUsageDescription = "Select passport/ID picture from photo album";
你也可以给 key 加上双引号(亲测),像下面这样
"NSCameraUsageDescription" = "Take passport/ID card photos to upload";
"NSPhotoLibraryUsageDescription" = "Select passport/ID picture from photo album";
功能权限对应的 key 可以通过以下方式获得,如图
实践过程中遇到的问题
- 我们工程有两个 target,所以建了两个 plist 文件。关于这两个 plist 文件,一开始我以为需要分别进行国际化,所以建了两个不同的 .strings 文件:InfoPlist.strings 和 AbroadInfoPlist.strings。调试我一直使用的是 AbroadInfoPlist.strings 对应的 target,导致怎么调试、更改都不行。网上资料难道都错了?究竟哪里不对了? 心里是万x驼奔腾!后来才发现名称必须得是 InfoPlist.strings。不过一下午的时间差不多都过去了!F...ck !
- 选中 info.plist 时右侧面板也有 Localize... 的选项,我也怀疑是不是通过这里进行 info.plist 的初始化。后面发现不行,info.plist 会分别生成对应语言的版本放到不同的 .lproj 文件(en.lproj 和 zh-Hans.lproj)中去。而 info.plist 需要在 build settings -> packaging -> info.plist File 中进行路径设置的。而且只能设置一个路径。所以这条路走不通,具有迷惑性,也浪费了我不少时间。
关于 info.plist 的国际化你也可以参考 https://www.jianshu.com/p/eb968d10e656
二. AFNetworking 调试时报错:Invalid parameter not satisfying: URLString
具体报错如下
Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Invalid parameter not satisfying: URLString'
起因
在做一个搜索界面,上方有一个搜索栏。用户输入之后的值会拼接到 path 的后面,如下
let path = "/api/search/\(inputText)"
后来发现是输入的有空格,导致的这个问题。解决方法,将输入框中输入的 inputText 做如下处理
let tmpKey = inputText.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
然后再拼接到 path 的后面去请求,就不会报错了!
这里有一个同样的问题:https://www.jianshu.com/p/e0da891a05da
三. 禁用 UITextView 的复制,剪切,选择,全选等功能
// 继承UITextView重写这个方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
// 返回NO为禁用,YES为开启
// 粘贴
if (action == @selector(paste:)) { return NO; }
// 剪切
if (action == @selector(cut:)) { return NO; }
// 复制
if (action == @selector(copy:)) { return NO; }
// 选择
if (action == @selector(select:)) { return NO; }
// 选中全部
if (action == @selector(selectAll:)) { return NO; }
// 删除
if (action == @selector(delete:)) { return NO; }
// 分享
if (action == @selector(share)) { return NO; }
return [super canPerformAction:action withSender:sender];
}
这里有一个讨论:https://www.itranslater.com/qa/details/2325748042663724032
四. NSUserDefaults 支持存储的数据类型
NSUserDefaults适合存储轻量级的本地数据。支持存储的数据类型有:NSNumber(NSInteger、float、double)、NSString、NSDate、NSArray、NSDictionary、BOOL。
五. Xcode 真机调试报错 Please reconnect the device
反复的重新连接手机,但就是运行报错。
具体报错如下:
Failed to prepare device for development.
If you are certain that Xcode supports development on this device, try disconnecting and reconnecting the device.
解决方案:
重启手机!!!
重启大法就是好,能解决很多疑难杂症!
六. App Store connect 中填写联系信息报 "此栏无效" 的错误
解决方法:
大 11 位电话号码前加地区号,像这样:+86-136xxxxxxxx
七. 如何取消 UIScrollView 的弹簧效果
scrollView.bounces = NO;
八、swift:Cannot convert value of type 'ArraySlice<UInt8>' to specified type '[UInt8]'
解决方案:Array(arr[2…<arr.count])
九、CUICatalog: Invalid asset name supplied
调试面板打印了许多如上所示的信息。
原因:使用[UIImage imageNamed:] 时,图片不存在或者传入的图片名为nil.
十、准确计算 UILabel 文本内容的高度
开发过程中,在使用 boundingRectWithSize:
方法计算字符串的行高时,发现由于文本内容是英文,计算出来的行高比实际显示的要小(中文可能没有这个问题)。经过后来揣摩观察发现是由于英文单词的换行是按照 NSLineBreakByWordWrapping
方式进行导致的,按照 NSLineBreakByCharWrapping
就没有问题。
如下图所示,蓝框右则的文本由于按单词换行导致没有顶格显示
解决方案:借助 NSMutableParagraphStyle 进行计算
示例代码如下
let str = attributedText.string
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byWordWrapping
// 加个换行符防止 str 不是分段落的文本内容,如果 str 不是分段落的文本内容下面的计算方式就无效
let tmpStr = "\(str)\n"
let tmpRect = tmpStr.boundingRect(with: CGSize(width: screenW - 32.0, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: [.font: font, .paragraphStyle: paragraphStyle], context: nil)
let height: CGFloat = ceil(tmpRect.height) + 1
问题完美解决!!! 学会了吗!