[TOC]
CocoaPods
Cocoapods 报错问题
- ERROR | [iOS] unknown: Encountered an unknown error (Could not find a `ios` simulator (valid values: ). Ensure that Xcode -> Window -> Devices has at least one `ios` simulator listed or otherwise add one.) during validation.
需要在Xcode中创建模板器
Cocoapods 配置问题
SDWebImage
SDWebImage 占位图是GIF处理
[cell.ImageView sd_setImageWithURL:[NSURL URLWithString:ImageUrl] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image == nil) {
UIImage *img = [UIImage sd_animatedGIFNamed:@"xxx.gif"];
cell.goodImgV.image = img;
}
}];
Xcode
Xcode10 打SDK库失败
解决方法,在脚本增加 -UseModernBuildSystem=NO ,原因是Xcode10使用新build系统,导致 xcodebuild 只会编译一个
相似的反馈:https://github.com/facebook/react-native/issues/19573
好像新build系统速度提升很好,了解更多新build系统: https://medium.com/xcblog/xcode-new-build-system-for-speedy-swift-builds-c39ea6596e17
Xcode10:library not found for -lstdc++.6.0.9 临时解决
Xcode 10中将libstdc++.6.0.9库文件删除,SDK依赖 libstdc++.6.0.9 的会在Xcode 10无法运行,解决方案:
https://blog.csdn.net/ZuoWeiXiaoDuZuoZuo/article/details/82756116?utm_source=copy
真机运行库
在终端输入以下命令打开Xcode的lib库目录(此目录位安装的默认目录)
open /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib
把刚刚下载的zip文件解压获取到的 真机的 libstdc++.6.0.9.tbd 文件,扔进去
模拟器运行库
在终端输入以下命令打开Xcode的lib库目录(此目录位安装的默认目录)
open /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib
把刚刚下载的zip文件解压获取到的 模拟器的 libstdc++.6.0.9.tbd 文件,扔进去
下一步
重启Xcode
在UILabel的NSAttributedText中创建可点击的“链接”?
- How to Create Multiple Tappable Links in a UILabel
- ios - Create tap-able "links" in the NSAttributedString of a UILabel? - Stack Overflow
Link With Standard Libraries > YES
默认是YES,编译器在链接时会自动使用标准库的链接器; 看官方的文档,如果设置为NO,需要配置 Other Linker Flags 来指定链接器。
Xcode 自定义快捷键
复制文件:
/Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Versions/A/Resources/IDETextKeyBindingSet.plist
增加自定义配置:
<key>Customized</key>
<dict>
<key>HTC Duplicate Current Line</key>
<string>selectLine:, copy:, moveToEndOfLine:, insertNewline:, paste:, deleteBackward:</string>
<key>HTC Delete Current Line</key>
<string>moveToEndOfLine:, deleteToBeginningOfLine:, deleteBackward:, moveDown:, moveToEndOfLine:</string>
<key>HTC Move Current Line Up</key>
<string>selectLine:, cut:, moveUp:, moveToBeginningOfLine:, insertNewLine:, paste:, moveBackward:</string>
<key>HTC Move Current Line Down</key>
<string>selectLine:, cut:, moveDown:, moveToBeginningOfLine:, insertNewLine:, paste:, moveBackward:</string>
<key>HTC Insert Line Above</key>
<string>moveUp:, moveToEndOfLine:, insertNewline:</string>
<key>HTC Insert Line Below</key>
<string>moveToEndOfLine:, insertNewline:</string>
</dict>
替换原来文件,重新打开Xcode,就可以搜索查看和定义快捷键
LLDB
LLDB 通用结构的形式如下:
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]
指令 | 全称 | 作用 |
---|---|---|
apropos | 帮助命令,通过 apropos + xxx 命令可以找到xxx所有相关的命令信息。 | |
p | 输出原生类型(boolean、integer、float、etc)的信息 | |
po | print object | 输出objective-c中对象(objects)的信息. (为 e -o 的别名) |
e | expression | 可以执行表达式。expression 其实就是 p/print/call、expression -o 就是 po 。 |
b | breakpoint | 设置断点. (可在运行过程中添加) |
br li | breakpoint list | 列出所有断点 |
breakpoint delete | 删除所有断点(可跟组号删除指定组) | |
breakpoint disable/enable | 禁用、启用指定断点 | |
breakpoint set -r some | 遍历整个项目中包含 some 这个字符的所有方法并设置断点 | |
c | continue | 单步调试 |
n | thread step-over/next | 当前线程下一步(以一个完整子函数为一步) |
ni | thread step-inst-over | 当前线程下一步(以一个汇编函数为一步) |
s | thread step-in/step | 当前线程下一步(遇到子函数就进入并且继续单步执行) |
si | thread step-inst-over | 当前线程下一步(遇到汇编函数就进入并且继续单步执行汇编指令) |
finish | thread step-out | 退出当前帧栈 |
image | 可用于寻址,有多个组合命令。常用于寻找栈地址对应的代码位置, 用于查错(能定位出错误代码行数)。 | |
image lookup | image lookup --address 0x1af8 :在可执行文件或任何共享库中查找原始地址信息。image lookup -v --address 0x1af8 :查找完整的源代码行信息。image lookup --type NSString :根据名称查找对应(NSString)类型的信息。 |
|
register read | 显示当前线程的通用寄存器。 | |
register write | register write rax 123 :将一个新的十进制值“123”写入当前线程寄存器“rax”。 |
|
memory read | memory read --size 4 --format x --count 4 0xbffff3c0 :从地址0xbffff3c0读取内存,并显示4个十六进制uint32_t值。 |
|
bt | thread backtrace | 打印调用堆栈 |
thread backtrace all | 列出所有线程的堆栈 | |
thread list | 列出所有线程 | |
thread return | 可用来控制程序流程, 伪造返回值 | |
frame variable | 获取全部变量值 | |
watchpoint | 监听某个实例的变化. (等同于在Xcode调试变量窗口—>右键某个变量—>Watch xx) 注意: watchpoint是分类型的,包括read,write或者read_write类型. 通过Xcode右键添加的只能是write类型. | |
Xcode xip 快速解压缩安装
如果你确定下载来源很安全的话(不安全的来源有出过事,见 XcodeGhost
事件),可以用指令跳过验证,就会快一些:
xip -x Xcode_12.4.xip
具体,执行命令后,没有图形界面,就是等:
xip -x /Users/iHTCboy/Downloads/Xcode_12.5_beta.xip
xip: signing certificate was "Development Update" (validation not attempted)
iOS
iOS 处理器指令集架构
2018 A12芯片arm64e : iphone XS、 iphone XS Max、 iphoneXR 2017 A11芯片arm64: iPhone 8, iPhone 8 Plus, and iPhone X 2016 A10芯片arm64:iPhone 7 , 7 Plus, iPad (2018) 2015 A9芯片arm64: iPhone 6S , 6S Plus 2014 A8芯片arm64: iPhone 6 , iPhone 6 Plus 2013 A7芯片arm64: iPhone 5S armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display) armv7:iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4 | iPod Touch5 ARMv6:iPhone, iPhone 3G, iPod 1G/2G
模拟器32位处理器测试需要i386架构, 模拟器64位处理器测试需要x86_64架构, 真机32位处理器需要armv7,或者armv7s架构, 真机64位处理器需要arm64架构。
- iPhone CPU架构 - 掘金
- iOS 指令集架构 armv6、armv7、armv7s、arm64、arm64e、x86_64、i386 - Belinda_sl - 博客园
- 关于Xcode “Build Setting”中的Architectures详解 - 崩月姐姐之家
- ios - Xcode arm64 Vs arm64e - Stack Overflow
- Armv8-A: 2016 additions - Processors blog - Processors - Arm Community
WKWebView如何清除缓存
- (void)deleteWebCache {
//allWebsiteDataTypes清除所有缓存
if (@available(iOS 9.0, *)) {
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
NSLog(@"[Web log]: deleteWebCache completion~");
}];
}
}
Home Indicator 问题
iOS证书&签名
从App里用代码读取证书信息
//取出embedded.mobileprovision这个描述文件的内容进行判断
NSString *mobileProvisionPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
NSData *rawData = [NSData dataWithContentsOfFile:mobileProvisionPath];
NSString *rawDataString = [[NSString alloc] initWithData:rawData encoding:NSASCIIStringEncoding];
NSRange plistStartRange = [rawDataString rangeOfString:@"<plist"];
NSRange plistEndRange = [rawDataString rangeOfString:@"</plist>"];
if (plistStartRange.location != NSNotFound && plistEndRange.location != NSNotFound) {
NSString *tempPlistString = [rawDataString substringWithRange:NSMakeRange(plistStartRange.location, NSMaxRange(plistEndRange))];
NSData *tempPlistData = [tempPlistString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *plistDic = [NSPropertyListSerialization propertyListWithData:tempPlistData options:NSPropertyListImmutable format:nil error:nil];
NSLog(@"plistDic: %@", plistDic);
}
通过Safari获取iOS设备真实UDID
- Configuration Profile Examples
- 通过Safari浏览器获取iOS设备UDID(设备唯一标识符) - FengHongSeXiaoXiang的博客 - CSDN博客
- shaojiankui/iOS-UDID-Safari: iOS-UDID-Safari,(不能上架Appstore!!!)通过Safari获取iOS设备真实UDID,use safari and mobileconfig get ios device real udid
自定义 iOS Web Clip 图标
genstrings命令与字符串本地化
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
[bundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \
[bundle localizedStringForKey:(key) value:(val) table:(tbl)]
方法:
NSLocalizedString(@"key", @"My comment")
/* My comment */
"key" = "value";
扫描当前文件夹下所有.m文件的宏,生成Localizable.strings文件并放到en.lproj文件夹下:
$ find . -name \*.m | xargs genstrings -o en.lproj
指定的输出目录下生成 TableName.strings
文件,然后添加记录和注释:
NSLocalizedStringFromTable(@"key", @"TableName", @"My comment")
下面三句的作用是一样的,都是读取苹果指定名字为 Localizable.strings
的内容,其中第三种简化后就是苹果对 NSLocalizedString
宏的定义:
NSLocalizedString(@"key", @"My comment");
NSLocalizedStringFromTable(@"key", @"Localizable", @"My comment");
NSLocalizedStringFromTable(@"key", nil, @"My comment");
Deferred Deep Linking in iOS
- iOS Deferred Deep Link 延遲深度連結實作(Swift) - ZRealm Dev. - Medium
- iOS App与浏览器深度链接 - 简书
- Deferred Deep Linking in iOS Swift 3.0 with Universal Link | InnovationM Blog
- Deferred Deep Linking in iOS
- Promoting Apps with Smart App Banners
- iOS10 SFSafariViewController not working when alpha is set to 0
App Groups 和 Keychain Access Groups
copy 和 mutableCopy 返回的对象是执行的深拷贝还是浅拷贝呢?
- 系统的非容器类对象,如: NSString、NSMutableString、NSNumber 等。
系统的容器类对象,如: NSArray、NSMutableArray、NSDictionary、NSMutableDictionary 等。
对于系统的非容器类对象,如果对一不可变对象(如 NSString)复制,copy 是指针复制(浅拷贝)和 mutableCopy 就是对象复制(深拷贝); 如果是对可变对象(如 NSMutableString)复制,copy 和 mutableCopy 都是深拷贝,但是 copy 返回的对象是不可变的。
- 对于系统的容器类对象,对不可变对象(如 NSArray)进行复制,copy 是指针复制(浅拷贝), mutableCopy 是对象复制(深拷贝), 但是不管是 copy 还是 mutableCopy, 且不论容器内对象是可变还是不可变,返回的容器内对象都是指针复制(浅拷贝)。
对于系统的容器类对象,对可变对象(如 NSMutableArray)进行复制时,copy 和 mutableCopy 都是对象复制(深拷贝),但是不管是 copy 还是 mutableCopy,且不论容器内对象是可变还是不可变,返回的容器内对象都是指针复制(浅拷贝)。
“const”和“static” 符号区别与联系
static NSString const * kUserName = @"iHTCboy";
static const NSString * kUserName = @"iHTCboy";
static NSString * const kUserName = @"iHTCboy";
const 修饰的是他右边的部分,也就是说:
static NSString const * kUserName = static NSString const (* kUserName )
static NSString * const kUserName = static NSString * const (kUserName)
当const修饰的是(userName)的时候,不可变的是userName;星号在C语言中表示 指针指向符,也就是说这个时候userName指向的内存块地址不可变,而内存保存的内容是可变的。
一定要同时使用static和const来定义你的变量 上面已经说了const是用来定义一个常量。而static在C语言中(OC中延用)则表明此变量只在改变量的输出文件中可用(.m文件),如果你不加“static”符号,那么编译器就会对该变量创建一个“外部符号”,后果是什么呢?
两个目标文件(.0文件是.m文件编译后的输出文件)有一个重复的符号。(OC中没有类似C++中的名字空间的概念),所以当你在你自己的.m文件中需要声明一个只有你自己可见的局部变量(k开头)的变量的时候一定要同时使用“static”和“const”两个符号。
定义工程中的全局变量
在”constants.h”文件中,声明常量:
extern NSString *const XUserName;
然后在“constants.m”中定义他:
NSString *const XUserName = @"iHTCboy";
这样做的优势是保持常量绝对不会被修改,并且一定初始化还带有类型信息。
获取 iOS 设备上安装的应用列表(非越狱)
- 私有API的使用 | Mark Miao
- 获取 iOS 设备上安装的应用列表 - Octree
- Retriever: 在未越狱的 iOS 设备上查看 app 的 InfoPlist - 知乎
- IOS 获取安装的app_骑着蜗牛找马儿-CSDN博客
- iOS11/iOS12上通过LSApplicationWorkspace获取应用列表(只能获取带有 plugin 的app) - iOSRE
Umbrella Framework
- Introduction to Framework Programming Guide
- iOS - Umbrella Header在framework中的应用 | Startry Blog
- OC和Swift混编Frameowork优雅指南 - 简书
- 用.modulemap实现模块化 - 简书
CFAbsoluteTimeGetCurrent() 和 CACurrentMediaTime() 区别
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
CFTimeInterval currentTime = CACurrentMediaTime();
CFAbsoluteTime absoluteTime = CFAbsoluteTimeGetCurrent();
NSLog(@"currentTime: %f, absoluteTime: %f", currentTime, absoluteTime);
currentTime: 697112.258945, absoluteTime: 612415143.769868
CACurrentMediaTime()
方法是QuartzCore框架里的,相对来说比较原子量,比较精确,可以用来测量程序的时间效率。获取到的时间是手机开机后的秒数,在模拟器上运行数值不必计较,算时间差就好。CFAbsoluteTimeGetCurrent()
方法是 CoreFoundation 框架中的,是获取2001年1月1日 00:00 GMT 开始的秒数。相当于上面的NSDate方法[NSDate timeIntervalSinceReferenceDate]
一样。- CFAbsoluteTimeGetCurrent() | Apple Developer Documentation
Block 的 Weak-Strong Dance
- 为什么
weak strong dance
能够避免循环引用? - 为什么不直接使用 weak?
- 使用
weak strong dance
的正确姿势?
weakSelf+strongSelf:
__weak typeof(self) weakSelf = self;
self.dataBlock = ^(NSString *title) {
__strong typeof(self) strongSelf = weakSelf;
strongSelf.titleLabel.text = title;
};
strongSelf
持有 self 的行为是在 Block 执行的时候进行的,所以多线程中,可能 weakSelf
指向的对象会在 Block 执行前被废弃。
所以,多线程环境下,最好在判断一下 strongSelf
不为 nil 在使用:
__weak typeof(self) weakSelf = self;
self.dataBlock = ^(NSString *title) {
__strong typeof(self) strongSelf = weakSelf;
if(strongSelf) {
strongSelf.titleLabel.text = title;
}
};
weakify + strongify:
weakify(self);
self.dataBlock = ^(NSString *title) {
strongify(self);
self.titleLabel.text = title;
};
weakify + strongify 定义:
#define weakify(var) __weak typeof(var) XYWeak_##var = var;
#define strongify(var) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
__strong typeof(var) var = XYWeak_##var; \
_Pragma("clang diagnostic pop")
- Why could weak-strong dance break retain cycle?
- Objective-C Advancements In-Depth - WWDC 2011 - Videos - Apple Developer
- 对 Strong-Weak Dance的思考
- iOS的weakSelf与strongSelf - 简书
- Swift中的Weak Strong Dance - 戴伟来的博客|DavidDay's Blog
- ARC与非ARC下的Weak-Strong Dance - okeyang's blog
- 你真的懂 weak strong dance 吗? | 冬天的冰激凌
- ios - Objective-C ARC: strong vs retain and weak vs assign - Stack Overflow
- Weak-Strong-Dance真的安全吗? - 简书
宏定义
逻辑分辨率和物理分辨率(Physical Resolution vs Logical Resolution)
分辨率(Resolution)
分辨率又称显示分辨率、屏幕分率。确定手机屏幕上显示多少信息的设置,以水平和垂直像素(pixel)来衡量。
inch(英寸)
1 inch= 2.54cm = 25.4mm
屏幕尺寸
屏幕大小的物理尺寸,以屏幕对角线的长度(diagonal)来衡量
PPI(像素密度,Pixels Per Inch)
表示沿着设备的对角线,每英寸所拥有的像素(pixel)数目,PPI的数值越高,代表显示屏能够以越高的密度显示图像,即通常所说的分辨率越高,颗粒感越弱,图像更清晰。 一个像素一个格子,“每英寸像素”,表示一英寸的长度有几个格子。
PPI的计算值 以 iPhone 8 为例,屏幕分辨率:750px X 1334px,屏幕尺寸:4.7 英寸
DPI(每英寸点数,Dots Per Inch) 用于打印机,“每英寸墨点”。
为什么不用宽高(width/height)各能容纳下多少颗像素? 因为用每英寸能容纳下多少颗像素,就可以在不同尺寸的屏幕用 PPI 来比较了。
13寸的屏幕,屏幕的分辨率是1280*720,如果物理分辨率改成了2560*1440的分辨率,相当于每个像素点的尺寸减少了4倍,原来在1280*720的一个像素内容,在2560*1440上则填充了4个像素,因此虽然内容显示还是一样多,但是屏幕精细度高了2倍,像素倍率是2,这下再也看不出颗粒感了
一粒像素有多大? 像素在脱离了屏幕尺寸之后是没有大小可言的 你可以将 1920 * 1080 颗像素放到一台 40 寸的电视里面,也可以将同样多的像素全部塞到一台 5.5 寸的 iPhone7 Plus 手机里面去,那么对于 40 寸的电视而言,每个像素颗粒当然会大于 5.5 寸的手机的像素。
所以光看屏幕的分辨率对于设计师来说是不具备多少实际意义的,通过分辨率计算得出的像素密度(PPI)才是设计师要关心的问题,我们通过屏幕分辨率和屏幕尺寸就能计算出屏幕的像素密度的。
Scale Factor(缩放因子) 为了方便开发人员开发,iOS 中统一使用点(Point)对界面元素的大小进行描述。 早期的iPhone3GS的屏幕屏幕分辨率是320 * 480,iOS绘制图形(CGPoint/CGSize/CGRect)均已point为单位。
1 point = scale*pixel
注:在iPhone4~6中,缩放因子scale=2;在iPhone6 plus中,缩放因子scale=3
- Designer's guide to DPI
- The Ultimate Guide To iPhone Resolutions
- iPhone 6 Screens Demystified
- 逻辑分辨率和物理分辨率到底是什么呀? - 知乎
- DPI 和 PPI 的区别是什么? - 知乎
- iOS UI设计 - 分辨率 屏幕尺寸 与 像素密度
- iPhone屏幕尺寸、分辨率及适配
- iOS 屏幕尺寸、逻辑分辨率、物理分辨率之间的相互关系
SDK 库相关命令
查看.a库文件所包含的架构库命令:
lipo -info XXXXX.a
合并多个架构:
lipo -create 真机路径 模拟器路径 -output 真机路径
从fat文件里面分离出来各个架构的库:
lipo -thin armv7 XXXXX.a -output XXXXX-armv7.a
查看库中所包含的文件列表:
ar -t armv7.a
从每个架构的.a文件中删除与其他sdk冲突的.o文件:
ar -d -sv XXXXX-armv7.a XXXX.o
注意:把每个架构的.a文件单独放一个文件夹进行解压命令,因为同一个sdk的不同架构库解压出来的.o文件同名会覆盖掉
目录下所有.o文件(用*.o)打包成.a文件:
ar -r *.o libxxx.a
使用 Xcode libtool 合并多个静态库:
xcrun -r libtool -no_warning_for_no_symbols -static -o output.a 1.a 2.a 3.a 4.a
- -no_warning_for_no_symbols 不输出 has no symbols 的警告
- -static 链接的类型为静态库
- -o 指定合并后的文件路径
xcrun -r libtool
: 使用 Xcode Toolchain 里的 libtool,直接运行 libtool 会使用 $PATH 的路径的
DFU 和 Recovery 模式
Recovery模式 恢复模式,也称 iBoot 模式,常用的使用场景就是手机需要刷机或者升降级的情况。操作该模式时,手机上会显示iTunes连接数据线的图标。
DFU模式 全称是 Device Firmware Upgrade,意思为固件的强制升降级模式,也叫开发者模式。
DFU模式一般是在手机无法使用Recovery模式(例如无法正常开机或者iTunes无法正常识别)的情况下使用,常见的场景就是我们在升级iOS系统手机出现白苹果或者黑屏的情况。
进入Recovery模式
- 方法一:直接连接iTunes,点击iTunes页面上的更新(升级最新版系统)或者【恢复iPhone】(刷机);
- 方法二:给手机进行升降级,刷入已下载的iOS 固件版本:连接iTunes,在电脑上按住【shift】键,同时点击iTunes上的【更新】,然后选择提前下载好的iOS 固件版本进行升降级;
进入DFU模式
- 把手机接到电脑上。
- 把手机关机。
- 按住电源键3秒。
- 不松开电源键,按住Home键10秒。(无实体 Home 键的用音量减小键)
- 松开电源键但保持按住Home键。(无实体 Home 键的用音量减小键)
- 5秒钟后松开松开Home键,直到屏幕保持黑屏。(如果屏幕显示“请连接iTunes”,说明你按的时间太长了,需要重新做一遍)
退出模式 同时按住电源键和 Home键(音量减小键),将设备重启即可退出恢复模式或者DFU模式。
注意:操作时,建议将手机数据提前进行备份哦!
NSArray 和 NSMutableArray
Toll-Free Bridging
There are a number of data types in the Core Foundation framework and the Foundation framework that can be used interchangeably. Core Foundation 框架和 Foundation 框架中有许多数据类型可以互换使用。
可以方便和谐的使用Core Foundation类型的对象和Objective-C类型的对象。
NSCFString 是 NSString 的私有子类,实现了 NSString 的所有方法。为什么要有CFString 呢?
CFString provides a suite of efficient string-manipulation and string-conversion functions. It offers seamless Unicode support and facilitates the sharing of data between Cocoa and C-based programs CFString提供了一套高效的字符串处理和字符串转换功能。它提供无缝的Unicode支持,并促进可可和基于C的程序之间的数据共享。
__bridge
(修饰符)__bridge_retained
(修饰符)和CFBridgingRetain
(函数)__bridge_transfer
(修饰符) 和CFBridgingRelease
(函数)
__bridge 类型转换时并不改变内存管理方式。只是声明类型转变,但是不做内存管理规则的转变。
CFStringRef s1 = (__bridge CFStringRef) [[NSString alloc] initWithFormat:@"Hello, %@!", name];
__bridge_retained(修饰符) or CFBridgingRetain(函数)
通过 __bridge_retained
,在 bridge 的时候,编译器会 retain Core Foundation 端的对象,之后由开发者负责手动管理内存,这样即使 Foundation 的变量被释放,也不会影响 Core Foundation 的变量的使用。
NSString *s1 = [[NSString alloc] initWithFormat:@"Hello, %@!", name];
CFStringRef s2 = (__bridge_retained CFStringRef)s1;
// do something with s2
//...
CFRelease(s2); // 注意要在使用结束后加这个
等同函数:
NSString *s1 = [[NSString alloc] initWithFormat:@"Hello, %@!", name];
CFStringRef s2 = (CFStringRef)CFBridgingRetain(s1);
// do something with s2
//...
CFRelease(s2); // 注意要在使用结束后加这个
__bridge_transfer(修饰符) or CFBridgingRelease(函数)
当从 Core Foundation 类型转换为 Foundation 类型时,编译器转移了对象的所有权,开发者不再需要负责 Core Foundation 端对象的内存管理。
CFStringRef result = CFURLCreateStringByAddingPercentEscapes(. . .);
NSString *s = (__bridge_transfer NSString *)result;
//or NSString *s = (NSString *)CFBridgingRelease(result);
// CFStringRef result 不用手动释放了
这里用 __bridge_transfer
将result的管理责任交给了ARC来处理,所以就不需要再显式地调用 CFRelease()
释放了。
- Toll-Free Bridging
- CFString | Apple Developer Documentation
- 深入理解Toll-Free Bridging_Leo的专栏-CSDN博客
- iOS开发ARC内存管理技术要点 - 不忘初“辛” - 博客园
__IPHONE_OS_VERSION_MAX_ALLOWED
、 __IPHONE_OS_VERSION_MIN_REQUIRED
和 __IPHONE_xx_x
__IPHONE_OS_VERSION_MAX_ALLOWED
:当前Xcode的系统SDK版本__IPHONE_OS_VERSION_MIN_REQUIRED
: 当前项目支持的最低支持的版本
作用:根据不同的开发环境编译不同的代码
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
//you can use iOS 8 APIs here because the SDK supports them
//but the code may still crash if run on an iOS 7 device
#else
//this code can’t use iOS 8 APIs as the SDK version doesn’t support them
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
//minimum deployment target is 8.0, so it’s safe to use iOS 8-only code
#else
//you can use iOS8 APIs, but the code will need to be backwards
// compatible it will crash when run after or on an iOS 7 device
#endif
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if ([NSURLSession class] &&
[NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) {
// ...
}
#endif
可以使用 __IPHONE_8_0
、__IPHONE_14_3
代替了数字。在 iOS SDK 目录下:usr/include/AvailabilityVersions.h
#define __IPHONE_13_0 130000
#define __IPHONE_13_1 130100
#define __IPHONE_13_2 130200
#define __IPHONE_13_3 130300
#define __IPHONE_13_4 130400
#define __IPHONE_13_5 130500
#define __IPHONE_13_6 130600
#define __IPHONE_13_7 130700
#define __IPHONE_14_0 140000
#define __IPHONE_14_1 140100
#define __IPHONE_14_2 140200
#define __IPHONE_14_3 140300
- AvailabilityInternal.h
- AvailabilityVersions.h
- AvailabilityVersions - Open Source
- Swift System Version Checking - NSHipster
- Swift System Version Checking - NSHipster - 中文
- Efficient iOS Version Checking | Inside PSPDFKit
- iOS开发之多系统版本兼容
Apple Worldwide Developer Relations Certification Authority
- Apple Root Certificate Authority
- Apple Worldwide Developer Relations Certification Authority
Apple Worldwide Developer Relations Certification Authority 的证书虽苹果颁发给iOS开发者的证书的根证书。而 Apple Worldwide Developer Relations Certification Authority 的证书的根证书是 Apple Root Certificate Authority 证书。
AppleWWDRCA.cer 就是开发者证书的根证书。它在安装Xcode的时候自动安装了。如果发现它失效了,需要到苹果公司官网下载并进行安装。
CSR文件: CSR(Certificate Signing Request) 是一个规范
- Apple Worldwide Developer Relations Intermediate Certificate - Support - Apple Developer
- Certificates - Support - Apple Developer
- WWDR Intermediate Certificate Expiration - Support - Apple Developer
- iOS证书
iOS 崩溃
iOS Swift5 获取某时间段内的所有日期
func getDaysDate(startDate: String,
endDate: String,
dateFormat: String = "yyyy-MM-dd HH:mm:ss",
outDateFormat: String = "yyyy/MM/dd") -> [String]
{
let formatter = DateFormatter()
formatter.dateFormat = dateFormat
let startTime = formatter.date(from: startDate)! // first date
let endTime = formatter.date(from: startDate)! // last date
let fmt = DateFormatter()
fmt.dateFormat = "yyyy/MM/dd"
var dayArray = [String]()
var date = startTime
var result = date.compare(endTime)
while result != .orderedDescending {
let day = fmt.string(from: date)
dayArray.append(day)
date = Calendar.current.date(byAdding: .day, value: 1, to: date)!
result = date.compare(startTime)
}
return dayArray
}
黑科技
刷单、苹果36技术
虚拟定位功能
- 苹果iPhone不越狱虚拟定位(多种方式,驱动更新至13.0) – Aneeo Blog
- iOS实现虚拟定位的多种玩法 - 掘金
- iOS虚拟定位:无需越狱,支持iPhone XS Max,支持12.2 - Flyzy's Blog