[TOC]
016
获取iOS设备uuid, 获取App bundleid
➜ ~ idevice_id -l
a82fecc1d3f1628f85e5055e238d8515f23624da
# 需要安装ideviceinstaller: brew install ideviceinstaller
➜ ~ ideviceinstaller -l
Total: 45 apps
com.tencent.xin - 微信 7.0.4.40
com.wmc-china.MemoryChampionshipsHD - 脑力大师 1.0.8
com.reederapp.iOS - Reeder 4000.39.01
com.xk72.Charles - Charles 95
is.workflow.my.app - 快捷指令 784
com.kapeli.dash.ios - Dash 400
com.sugarmo.ScrollClip - Picsew 2911
com.apple.TestFlight - TestFlight 6
com.netease.mailmasterpro - 网易邮箱大师 1429
com.baidu.map - 百度地图 10.15.0.7
com.moke.Annotable - Annotable 150
015
代码阅读target-action
(lldb) e id $view = (id) 0x7fbd71432590
(lldb) po [$view allTargets]
{(
)}
(lldb) po [$button actionsForTarget:(id)0x7feff2d67330 forControlEvent:0]
014
自动打包遇到的问题
当Team:Personal Team is not enrolled in the Apple Developer Program时,下面的命令导出ipa失败
失败原因${options_plist}所指定的文件中method
字段写为了ad-hoc
,修改为development
就ok了
xcodebuild -exportArchive -archivePath ${archive_path} -exportPath ${ipa_path} -exportOptionsPlist ${options_plist}
上面命令的失败输出:
error: exportArchive: No signing certificate "iOS Distribution" found
Error Domain=IDECodesignResolverErrorDomain
Code=1 "No signing certificate "iOS Distribution" found"
UserInfo={
IDEProvisioningError_UserInfoKey_IDEProvisioningErrorPlatform=com.apple.platform.iphoneos,
IDEProvisioningError_UserInfoKey_IDEProvisioningErrorAction=5,
NSLocalizedRecoverySuggestion=No "iOS Distribution" signing certificate matching team ID "P9DNHPPVMB" with a private key was found.,
IDEProvisioningError_UserInfoKey_IDEProvisioningErrorSpecifier=iOS Distribution,
IDEProvisioningError_UserInfoKey_IDEProvisioningErrorTeam=,
NSLocalizedDescription=No signing certificate "iOS Distribution" found
}
-exportOptionsPlist
可以指向一个plist文件,文件内容大致如下:
teamID
P9DNHPPVMB
method
ad-hoc
uploadSymbols
provisioningProfiles
com.jason.abcdefg
6ce1bd8e-21b4-43c0-a00c-5aa86e131b45
:
xxxx.mobileprovision[6ce1bd8e-21b4-43c0-a00c-5aa86e131b45.mobileprovision]
Xcode把Profiles下载到如下目录:
~/Library/MobileDevice/Provisioning Profiles
mobileprovision是二进制文件无法查看, 可以用如果下的命令查看文件内容
security cms -D -i 6ce1bd8e-21b4-43c0-a00c-5aa86e131b45.mobileprovision
AppIDName
XC com jason abcdefg
ApplicationIdentifierPrefix
P9DNHPPVMB
DeveloperCertificates
MIIFmjCCBIKgAwIBAgIISlCOHuhedtMwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwNzIyMjM0NzMzWhcNMTkwNzIyMjM0NzMzWjCBjTEaMBgGCgmSJomT8ixkAQEMCk5OTDNENUg4MjIxOzA5BgNVBAMMMmlQaG9uZSBEZXZlbG9wZXI6IHpob3VqaWVfOTAzQDE2My5jb20gKFRDRExWRkVRSEopMRMwEQYDVQQLDApQOUROSFBQVk1CMRAwDgYDVQQKDAfmnbAg5ZGoMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPer0ggVn8D+jjuhHTxyFex3bk1Dp+Oxz7115mFwmwKwn0w7/RFFg87NpL3nGZA5FPpLdJfDPdZiVoNMcKA5Tl+KQRH9FYXENtli/Bn2/VEt9Cv8QQH71h26/U/mKtkBZCtxP4nR52v36naheUCS+2vB9UUy0Ndm2FnobegD8biJlJqtNFVYXTAQ+F/kJEnuLwWcr/uWmq4iteUvQxIOBkGlguw2g6Auw7/TjA1/6HGPaVsX3Tpz/M7A2I7nUB6QU54Z+sGnuMSJbelzwx8o1UyXTzgmuxaPMPUyARUETcDBKZLQ0QLNAkUCNpl1Ss6zv5trE06mbelquKBXp3BdUncCAwEAAaOCAfEwggHtMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLXd3ZHIwMTCCAR0GA1UdIASCARQwggEQMIIBDAYJKoZIhvdjZAUBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFHuh/bXHzpKtVf6EXpIIYrQ2j19hMA4GA1UdDwEB/wQEAwIHgDATBgoqhkiG92NkBgECAQH/BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAo9AA9R9Lg6f77WY4n51KgP8MMHaEdDKmuji/sdHVhqCpMqfGdcVmweE2lp4M38g/SD2diOFL4YhXdlwG3e1jc68L8GIvfT+AeaAk3G2K7D6Ew6iR4vmAmWTUKbb8OIN7a5KGALKABfwAEDHynJnN+x2n7yCsQtlf1pF8vkYgmewDAeBPqc2ruq9WvxIcRDsAixEr0/f08zzohHSK0omAYSuKTd85UqRnZ1QUSbrDIG2U+H0qiS+0Qw4xyCHjlqtWRbMaoEppowcjgah8Llnp0Lel56mW0l4iMZdbHlRpsDbA+gX1tPeJN5ztvnNEjawDDQ8tT+U3RW7OcWrcIq43Cg==
Entitlements
keychain-access-groups
P9DNHPPVMB.*
get-task-allow
application-identifier
P9DNHPPVMB.com.jason.abcdefg
com.apple.developer.team-identifier
P9DNHPPVMB
ExpirationDate
2018-11-01T11:22:49Z
Name
iOS Team Provisioning Profile: com.jason.abcdefg
ProvisionedDevices
a82fecc1d3f1628f85e5055e238d8515f23624da
TeamIdentifier
P9DNHPPVMB
TeamName
杰 周
UUID
6ce1bd8e-21b4-43c0-a00c-5aa86e131b45
Xcode 10生成的ExportOptions.plist
compileBitcode
method
development
signingStyle
automatic
stripSwiftSymbols
teamID
P9DNHPPVMB
thinning
<none>
013
iOS 中的数组排序操作
NSLiteralSearch
区分 同一个字符(如日文的片假字)的半角与全角状态[半角状态 > 全角状态]
NSWidthInsensitiveSearch
不区分 同一个字符(如日文的片假字)的半角与全角状态[半角状态 = 全角状态]
同时指定两个时,NSWidthInsensitiveSearch 比 NSLiteralSearch 的优先级高,综合起来的结果: [半角状态 = 全角状态]
NSForcedOrderingSearch
NSForcedOrderingSearch 的优先级最高
参考iOS 中的数组排序操作
012
工作线程中销毁对象
对象的销毁虽然消耗资源不多,但累积起来也是不容忽视的。通常当容器类持有大量对象时,其销毁时的资源消耗就非常明显。同样的,如果对象可以放到后台线程去释放,那就挪到后台线程去。这里有个小 Tip:把对象捕获到 block 中,然后扔到后台队列去随便发送个消息以避免编译器警告,就可以让对象在后台线程销毁了
NSArray *tmp = self.array;
self.array = nil;
dispatch_async(queue, ^{
[tmp class];
});
引用自iOS 保持界面流畅的技巧
011
beginIgnoringInteractionEvents
UIApplication.shared.beginIgnoringInteractionEvents()
pvc.setViewControllers([vc], direction: dir, animated: true) { _ in
UIApplication.shared.endIgnoringInteractionEvents()
}
In that code, I turn off user interaction when the page animation starts and turn it back on when the animation ends. The reason is that otherwise we can crash (or get into an incoherent state) if the user taps during the animation.
applicationWillTerminate:不一定被调用
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app.
For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason
像阅读类应用如:咪咕阅读、掌阅、QQ阅读有朗读功能,开启了Background Modes:
开启后进入后台一段时间,app被杀掉,applicationWillTerminate就不一定被调用
010
UIScrollView的scrollRectToVisible: animated:方法应用
UIScrollView的scrollRectToVisible: animated:NO 可以使用UIScrollView立即停止滑动,而用设置contentOffset的方法,还会滑动一会儿。见图:
代码如下:
009
iphone5 iOS7上UIScrollView的contentSize不能设置为CGFLOAT_MAX
最近在做阅读的上下滑动翻页功能,自然想到了UIScrollView
为了能无限翻页,把UIScrollView.contentSize = CGSizeMake(width, CGFLOAT_MAX)
测试发现在iphone5 iOS7崩溃
解决方法:
UIScrollView.contentSize = CGSizeMake(width, 2^31);
可能原因是iphone5 iOS7是32位,不能大于2^32
008
JSQMessages的问题在iOS11上崩溃的问题
JSQMessagesComposerTextView(@interface JSQMessagesComposerTextView : UITextView
)有个属性:
@property (weak, nonatomic, nullable) id
在iOS11上崩溃,原因:
@protocol UITextPasteConfigurationSupporting
@property (nonatomic, weak, nullable) id pasteDelegate;
@end
@interface UITextView ()
@end
UITextView实现了UITextPasteConfigurationSupporting协议,而UITextPasteConfigurationSupporting定义了pasteDelegate,JSQMessagesComposerTextView定义的pasteDelegate与系统的冲突了
解决方法:
修改JSQMessagesComposerTextView的pasteDelegate为jsq_pasteDelegate
007
NSKeyedUnarchiver在iOS8下读取plist的问题
v7.3.0前用:
[NSArray writeToFile:savedFileName atomically:YES]
来保存搜索记录;是一个plist文件
v7.3.1后用:
[NSKeyedArchiver archiveRootObject:array toFile:savedFileName]
来保存搜索记录;是一个二进制文件
savedFileName都是同一个文件,在v7.3.1上覆写了v7.3.0的plist文件为二进制文件
在iOS8.4下的系统用如下代码读取文件时,崩溃;但iOS10以上正常
NSMutableArray *recordArray;
recordArray = [NSKeyedUnarchiver unarchiveObjectWithFile:savedFileName];
if (recordArray == nil) {
//旧数据提取
recordArray = [NSMutableArray arrayWithContentsOfFile:savedFileName];
}
为了让全部iOS版本都正常,修改代码如下:
NSMutableArray *recordArray;
@try {
recordArray = [NSKeyedUnarchiver unarchiveObjectWithFile:savedFileName];
if (recordArray == nil) {
//旧数据提取
recordArray = [NSMutableArray arrayWithContentsOfFile:savedFileName];
}
}
@catch (NSException* e) {
recordArray = [NSMutableArray arrayWithContentsOfFile:savedFileName];
}
006
状态栏样式引起的神样问题
问题描述:
- UINavigationController里的2个ViewController:XXPlayerViewController, XXDownloaderManagerViewController.
- XXPlayerViewController不显示NavigationBar,preferredStatusBarStyle方法返回UIStatusBarStyleLightContent
- XXDownloaderManagerViewController显示NavigationBar,没有重写preferredStatusBarStyle方法,默认返回UIStatusBarStyleDefault
ViewController | NavigationBar | preferredStatusBarStyle |
---|---|---|
XXPlayer | Hide | UIStatusBarStyleLightContent |
XXDownloaderManager | Show | UIStatusBarStyleDefault |
步骤:XXDownloaderManagerViewController侧滑显示XXPlayerViewController,侧滑取消,并马上点击NavigationBar的“返回”按键
问题:XXPlayerViewController显示了XXDownloaderManagerViewController的UINavigationItem
解决方法:自定义的UINavigationController实现如下方法
- (UIViewController *)childViewControllerForStatusBarStyle {
return self.topViewController;
}
参考:Bug when swiping from view with uinavigationbar to one without
005
AVAudioSessionRouteChangeNotification一般不在主线程通知
AVAudioSessionRouteChangeNotification一般不在主线程通知,需要注意多线程问题
004
iOS7上的问题02
speedSlider已创建,并在视图层次中,创建时minimumTrackTintColor,maximumTrackTintColor不为代码中的颜色,这时候调整值(比如应用设置成夜间模式),在iOS7上不生效
//UISlider *speedSlider
self.speedSlider.minimumTrackTintColor = RGB_COLOR(200, 100, 100);
self.speedSlider.maximumTrackTintColor = RGB_COLOR(195, 206, 217);
iOS7上的问题01
有这么个函数:
- (void)showMainViewController:(NSInteger)pageIndex
{
}
它有一个参数:(NSInteger)pageIndex,在iOS7上,如下调用会有问题:
//targetVC实现了showMainViewController:方法
[targetVC performSelector:@selector(showMainViewController:) withObject:@0];
//或
[targetVC performSelector:@selector(showMainViewController:) withObject:[NSNumber numberWithInteger:0]];
问题:pageIndex的值不为0,更像一个内存地址
解决方法:
((void(*)(id, SEL, NSInteger))objc_msgSend)(targetVC, @selector(showMainViewController:), 0);
003
Locale改变 NSCurrentLocaleDidChangeNotification
- 通用-日期与时间-24小时制,收到通知
- 通用-日期与时间-时区,不会收到通知
- 通用-语言与地区-日历,不会收到通知
- 通用-语言与地区-地区,杀死应用程序
- 通用-语言与地区-iPhone语言,杀死应用程序
- 通用-语言与地区-温度单位,收到通知
002
让特定UICollectionViewCell滚到可见范围内
问题:调用UICollectionView scrollToItemAtIndexPath: atScrollPosition: animated:
不能让Cell滚到可见范围内
方法:可以这么调用:
[UICollectionView performBatchUpdates:^{
[UICollectionView scrollToItemAtIndexPath: atScrollPosition: animated:];
} completion:nil];
001
不要在applicationDidEnterBackground做长时间操作
1. 按Home键进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application
{
sleep(10);//模拟长时间操作
}
2. 1秒后点击应用进入前台,应用能显示
3. 这时点击界面是没有响应的
4. 10秒后applicationWillEnterForeground,applicationDidBecomeActive才被调用
NSLiteralSearch
区分 同一个字符(如日文的片假字)的半角与全角状态[半角状态 > 全角状态]
NSWidthInsensitiveSearch
不区分 同一个字符(如日文的片假字)的半角与全角状态[半角状态 = 全角状态]
同时指定两个时,NSWidthInsensitiveSearch 比 NSLiteralSearch 的优先级高,综合起来的结果: [半角状态 = 全角状态]
NSForcedOrderingSearch
NSForcedOrderingSearch 的优先级最高
000
NSString enumerateSubstringsInRange: options: usingBlock:可以断句
应用场景:咪咕阅读,掌阅等朗读时分句子高亮
[string enumerateSubstringsInRange:NSMakeRange(0, string.length)
options:NSStringEnumerationBySentences | NSStringEnumerationLocalized
usingBlock:block];
比如:完整的内容为:
或格式化显示:
断句后的结果: