CocoaPods
关于.gitignore 当你执行 pod install 之后,除了 Pod le 外,CocoaPods 还会生成一个名为 Podfile.lock 的文件,你不应该把这个文件加入到.gitignore 中。因为 Podfile.lock 会锁定当前各依 赖库的版本,之后如果多次执行 pod install 不会更改版本,要执行 pod update 才会改变 Podfile.lock。这样多人协作的时候,可以防止第三方库升级时造成大家各自的第三方库版 本不一致。 CocoaPods 的一篇 官方文档(http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ig nore-the-pods-directory-in-source-control) 也在 What is a Podfile.lock 一节中介绍了 Pod- file.lock 的作用,并且指出: is le should always be kept under version control.
reveal
reveal查看自己的项目UI结构,用xcode自带的debug view hierarchy看层次图就好了,只是不能修改,reveal可修改即时查看。 看别人的应用,需要越狱。
切图软件slicy
表示破解版没有找到。。但是发现了好用的PS插件:cutterman,选中要切的图层,可以直接导出iOS,Android,PC切图。关键不用破解,免费啊!
内存管理
底层CoreFoundation仍需要手动管理内存: __bridge:只做类型转换,不修改相关对象的引用计数,原来的 Core Foundation 对象在 不用时,需要调用 CFRelease 方法。 • _bridgeretained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对 象在不用时,需要调用 CFRelease 方法。 • _bridgetransfer:类型转换后,将该对象的引用计数交给 ARC 管理,Core Foundation 对象在不用时,不再需要调用 CFRelease 方法。
系统提供的 dispatch 方法
// 后台执行:dispatch_async(dispatch_get_global_queue(0, 0), ^{ // something });
// 主线程执行: dispatch_async(dispatch_get_main_queue(), ^{ // something });
// 一次性执行:static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // code to be executed once });
// 延迟2秒执行:double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // code to be executed on the main queue after delay });
安全性问题
需要在移动应用的网络通讯、本地文件和数据、源代码三方面做好防范,只有这样才能保证 应用的安全。
网络安全
- 安全地传输用户密码:1.加密 2.不要明文传输。 >另外GET 的 URL 数据一般都会保存在服务器的 access log 中,所以黑客一旦攻破服务 器,只需要扫描 acesss log,则可以轻易获得所有用户的明文密码。
正确的做法应该是这样:
事先生成一对用于加密的公私钥,客户端在登录时,使用公钥将用 户的密码加密后,将密文传输到服务器。服务器使用私钥将密码解密,然后加盐 (Salt:在密 码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密 码的散列结果不相符) 之后再多次求 MD5,之后再和服务器原来存储的用同样方法处理过的 密码匹配,如果一致,则登录成功。这样,黑客即使截获了加密后的密文,由于没有私钥, 也无法还原出原始的密码。而服务器即使被黑客攻陷,黑客除了暴力尝试,也无法从加盐和 多次 MD5 后的密码中还原出原始的密码。这样就保证了用户密码的安全。
-
防止通讯协议被轻易破解
开发者可以选择类似Protobuf,Google 提供的一个开源数据交换格式,其最大的特点是基于二进制,因此比传统的 JSON 格式要小得多,之类的二进制通讯协议或者自己实现通讯协议,对于传输的内容进行一定 程度的加密,以增加黑客破解协议的难度。
- 验证应用内支付的凭证 >因为苹果为了保护用户的隐私,支付凭证中并不包含用户的任何账 号信息,所以我们的应用和服务器无法知道这个凭证是谁买的,而只能知道这个凭证是真 的还是假的。
所以,对于应用内支付,开发者除了需要仔细地验证购买凭证外,也需要告知用户在越狱手 机上进行支付的风险。
本地文件和数据
- 程序文件的安全
混合开发模式,由于 iOS 安装文件其实就是一个 zip 包,所以我们可以通过解压,看到包内的内容。通过分析这些 JavaScript 文件,黑客可以比较 轻松地知道其调用逻辑,在越狱手机上,还可能修改这些 JavaScript 代码,以达到攻击的目 的。
通过将 JavaScript 源码进行混淆和加密,可以防止黑客轻易地阅读和篡改相关的逻辑,也可 以防止自己的 Web 端与 Native 端的通讯协议泄漏。
-
本地数据安全
iOS 应用的数据在本地通常保存在本地文件或本地数据库中。如果本地的数据未进行加密处 理,很可能被黑客篡改。
-
源代码安全 对于 反编译这类工具,我们的应对措施就比较少了。除了可以用一些宏来简单混淆类名外,我 们也可以将关键的逻辑用纯 C 实现。例如微信的 iOS 端的通讯底层,就是用 C 实现的。这 样的方式除了能保证通讯协议安全外,也可以在 iOS 和 Android 等多个平台使用同一套底层 通讯代码,达到复用的目的。
单一功能原则
我们应该把功能拆分, 把不同的功能都放到各自不同的类里面。
对于一个复杂的排版引擎来说,可以将其功能拆成以下几个类来完成: 1. 一个显示用的类,仅负责显示内容,不负责排版。 2. 一个模型类,用于承载显示所需要的所有数据。 3. 一个排版类,用于实现文字内容的排版。 4. 一个配置类,用于实现一些排版时的可配置项。
注:“单 一 功 能 原 则”(Single responsibility principle) ! 参 考链接:
收起键盘
除了调用相应控件的 resignFirstResponder 方法外,还有另外三种办法:
- 重载 UIViewController 中的 touchesBegin 方法,然后在里面执行 [self.view endEdit- ing:YES];,这样点击 UIViewController 的任意地方,就可以收起键盘。
- 直接执行[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];,用于在获得当前 UIViewController 比较困难的时候 192 | 实战技巧 用。
- 直接执行 [[[UIApplication sharedApplication] keyWindow] endEditing:YES]。
iOS6 以后不建议你将 view 置为 nil 的原因如下:
- UIView 有一个 CALayer 的成员变量,CALayer 是具体用于将自己画到屏幕上的。如下图 所示: {% img /images/viewdidunload-2.jpg %}
- CALayer 是一个 bitmap 图像的容器类,当 UIView 调用自身的 drawRect 时,CALayer 才 会创建这个 bitmap 图像类。
- 具体占内存的其实是一个 bitmap 图像类,CALayer 只占 48Bytes, UIView 只占 96Bytes。而 一个 iPad 的全屏 UIView 的 bitmap 类会占到 12MB 的大小!
- 在 iOS6 中,当系统发出 MemoryWarning 时,系统会自动回收 bitmap 类。但是不回收 UIView 和 CALayer 类。这样既能回收大部分内存,又能在需要 bitmap 类时,通过调用 UIView 的 drawRect: 方法重建。
苹果的操作系统对上面的内存回收还做了一个优化:
- 当一段内存被分配时,它会被标记成“In use”, 以防止被重复使用。当内存被释放时, 这段内存会被标记成“Not in use”,这样,在有新的内存申请时,这块内存就可能被分 配给其他变量。
- CALayer包括的具体的bitmap内容的私有成员变量类型为CABackingStor(e http://blog.spacemanlabs.com/20 internals-contents/ ),当收到 MemoryWarning 时,CABackingStore 类型的内存区会被标 记成 volatile 类型(这里的 volatile 和 C 及 Java 语言的 volatile 的意思不同),volatile 表示, 这块内存可能被再次被原变量使用。 这样,有了上面的优化后,当收到 MemoryWarning 时,虽然所有的 CALayer 所包含的 bitmap 内存都被标记成 volatile 了,但是只要这块内存没有被复用,当需要重建 bitmap 内存时,它 就可以直接被复用,而避免了再次调用 UIView 的 drawRect: 方法。
Xcode快捷键
cmd + shift + o 快速查找类,通过这个可以快速跳转到指定类的源代码中
ctrl + 6 列出当前文件中所有的方法,可以输入关键字来过滤。
使用脚本提高开发效率
删除未使用的图片资源 使用前需要先 brew install ack,安装一个名为 “ack”的命令行工具:
for i in `find . -name "*.png" -o -name "*.jpg"`; do
file=`basename -s .jpg "$i" | xargs basename -s .png | xargs basename -s @2x`
result=`ack -i "$file"` if [ -z "$result" ]; then
echo "$i"
# 如果需要,可以直接执行删除: # rm "$i"
fi done
Tagged Pointer
对于 64 位程序,引入 Tagged Pointer 后,相关逻辑能减少一 半的内存占用、3 倍的访问速度提升,以及 100 倍的创建、销毁速度提升。
当 8 字节可以承载用于表示的数值时,系统就会以 Tagged Pointer 的方式生成指针, 如果 8 字节承载不了时,则又用以前的方式来生成普通的指针。
苹果引入 Tagged Pointer,给 64 位系统带来了内存的节省和运行效率的提高。Tagged Pointer 通过在其最后一个 bit 位设置一个特殊标记,用于将数据直接保存在指针本身中。因为 Tagged Pointer 并不是真正的对象,我们在使用时需要注意不要直接访问其 isa 变量。
block
在 Objective-C 语言中,一共有 3 种类型的 block:
1. _NSConcreteGlobalBlock,全局的静态 block,不会访问任何外部变量。
2. _NSConcreteStackBlock,保存在栈中的 block,当函数返回时会被销毁。
3. _NSConcreteMallocBlock,保存在堆中的 block,当引用计数为 0 时会被销毁。
- 使用命令行查看block实现。
命令行中输入 clang -rewrite-objc XX.c,即可在目录中看到 clang 输出了一个 名为"XX.cpp"的文件,该文件就是 block 在 C 语言中的实现。
- 在 block 内部修改变量 a 的内容,不会影响外部的实际变量 a
方法中增加一个变量,在 block 中引用的变量,实际是在申明 block 时,被复制到 _mainblockimpl0 结构体中的那个变量。
- 在变量前面增加 __block 关键字
源码中增加一个结构体,用来保存我们要 capture 并且修改 的变量 引用的是该结构体的指针,因此可以修改外部变量。
- __weak
由于 block 会复制外部的变量,所以如果不注意,会比较容易造成循环引用。对于这种问题, 需要将引用的一方变成 weak 的,从而避免循环引用
ARC 对 block 类型的影响
在 ARC 开启的情况下,将只会有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 类型 的 block。原本的 NSConcreteStackBlock 的 block 会被 NSConcreteMallocBlock 类型的 block 替代。
"我认为这么做的原因是,由于 ARC 已经能很好地处理对象的生命周期的管理,这样所有对 象都放到堆上管理,对于编译器实现来说,会比较方便。"