写给前端看的 iOS 梳理 (上)
Categories: Study
20161020 摄于杭州西湖 Apple Store
序
去年双十一为了排查一些 Weex 性能问题开始接触 iOS 相关学习,恰逢今年 1 月份开始慢慢参与 iOS 业务开发,借此机会整理一下 iOS 开发中的一些基础知识,用于备忘,同时旨在通过系列文章让前端同学在日后碰到 iOS 的代码可以看懂,方便更好的理解端上的一些原理。
大纲
《上》主要讲述在 iOS 的开发过程中碰到的文件格式和 Foundation 框架常用的类,《中》和《下》正在整理中
文件格式
- .h: 头文件也叫接口文件,提供对外访问的接口,包含类、方法和属性的声明,相当于类的用户手册
- .m: 实现文件,用于实现
.h
中声明的方法,相当于类的工程细节 - Podflie: 包管理文件,用于定义项目所需要使用的第三方库,类比
package.json
- Podflie.lock: 依赖库锁文件,记录了需要被安装的 pod 的每个已安装的版本,便于团队协作包统一,类比
package-lock.json
- .xib: 可视化文件,一个轻量级的用来描述局部界面的文件
- .storyboard: 界面布局文件,承载对应 UIView 的视图控件
- .pch: 预编译头文件,将一个工程中“不会常修改”代码预先编译好放到 pch 里面,用于存放公用宏、存放公用头文件、还可以管理日志输出
- .plist: 属性列表文件,一种用来存储串行化后的对象的文件,通常用于储存用户设置或者一些捆绑的信息,也是数据持久化解决方案之一
- .lproj: 多语言本地化文件夹,也即为每一种语言单独定义一份资源,有图片,文本,Storyboard,Xib 这些文件
- .xcassets: 图像资源文件,用了存放图片资源
- .xcodeproj: Xcode 工程文件,存储着 Xcode 工程的各项配置参数
- .xcworkspace: Xcode 工程文件,使用 pod install 后生成的新文件,打开后可以同时看到项目文件和 pods 依赖包
Foundation 框架
简要介绍
首先介绍一下 Cocoa,Cocoa 是一套 OS X 和 iOS (Cocoa Touch) 中的框架和运行时支持,也即 API 应用程序接口,可类比于 VC 里面的 MFC。
Cocoa 其中最重要和 UIKit(OSX 为 AppKit) 和 Foundation,两个框架在系统中的位置如下图, 同时可以看到常见的框架所在位置。
其中 UIKit 主要用于 iOS 界面构建的,后面详细介绍。
Foundation 框架给我们框架和 App 开发提供了基础层功能,用于访问基本的数据类型,集合和操作系统服务,包括如下:
- 数据存储和持久化:NSArray、NSDictionary 以及 NSSet 为任何类的 OC 对象提供存储
- 文本和字符串处理:NSCharacterSet 用于 NSString 和 NSScanner 类中字符串各种操作
- 文件处理:NSFileManager 类 提供大量用于文件操作检查的方法
- 日期和日期:NSDate、NSTimeZone 和 NSCalendar 类
- URL 操作:提供一组类和协议来处理 URL 访问
- 异常处理:NSException 类
Foundation 在 JS 里面可以假想成一个原生的公用 Util 库,But 没有…
开始之前
OC 中@
是做什么的 ?
- 通常字符串前面会加一个
@
,用来将一个 C 语言的字符串转化为 OC 中的字符串对象 NSString @
符号 OC 中大部分的关键字都是以@
开头的,比如@interface
,@implementation
,@end
@class
等
很多类之前的 NS 前缀是什么 ?
- 在 OC 里不支持命名空间,所以只能通过加前缀这种土土的方法来避免命名冲突,所以常常会用 3 个大写字母(2 个的被苹果占了),可譬如开发者名称、公司名称或者方法名等来区分
- NS 代表的是 NeXTSTEP,为 NeXT 公司开发的操作系统,NeXT 是 Jobs 在 1985 年离开苹果时候创建的公司名称,后来被收购回来后,很多成果被吸收到 OSX 基础中
- 类似的还有,CF == Core Foundation;CG == CoreGraphics.frameworks;CA == CoreAnimation.frameworks;UI == UIKit 等表示
对象的可变性
OC 中的类可分为可变(mutable)类和不可变(immutable)类,这里不可变指的是字符串在内存中占用的存储空间固定,并且存储的内容不能发生变化,反之可变是指占用空间可不固定,内容可修改;这个和灵活的 JS 是很不一样的,但我更倾向于对数据类型区分可变和不可变,也便于后续的维护和扩展。
对于确定不会改变的类,它只具备应有的属性方法,可变类通过继承原有不变类,再增加可变方法属性即可实现可变。
可变类是不可变类的子类,同时所有可变类的实例对象可以作为不可变的实例对象来使用。
NSString
在 OC 中使用 NSString 来表示字符串,可变 NSMutableString 继承不可变 NSString 类,好比一个字符串链表,可对其进行 增删改 操作。
NSArray
在 OC 中使用 NSArray 来表示数组类, 这里需要注意的是它不像 JS 的数组可以存入任何类型,在 NSArray 中只能够存入 OC 对象,同时也是不可变的,假如需要更改数组,需要使用它的子类 NSMutableArray。
通过arrayWithObjects
方式创建的数组记得在最后一项加上nil
,所以为了方便更推荐直接使用@[@"lnj", @"lmj", @"jjj"]
方式创建,但是因为生成的是不可变数组,故在 NSMutableArray 中不要这么创建。
很多数组的操作方法和在 JS 中对比大致相同,不过 NSMutableArray 提供了比 JS 中一些更丰富的方法,包括交互两个元素位置这种需要自己写的方法,也即很多时候编写时候可以先查查文档看是否有这个方法, 很多时候可以从里面找到。
NSDictionary
前端同学第一次听到字典
这个词可能会有些陌生,可以类比 JS 中的 Object, Java 中的 Map,字典中的数据也是通过键值对保存。
NSDictionary 属于不可变字典类,一般创建之后只能用于查询,不能对其进行修改操作,想修改需要使用 NSMutableDictionary 类。
NSDate
NSDate 可以用来表示时间, 用来进行一些常见的日期时间的处理,它的使用方式和 JS 的 Date 也是很相似的,[NSDate date]
返回的就是当前时间,但是在格式化日期时间上面 Foundation 处理比 js 要优雅很多,直接调用其内置方法即可。
通过和 NSDateFormatter 类配合使用可以格式化日期,stringFromDate
用于 NSDate 转 NSString,dateFromString
用于 NSString 转 NSData:
假如想在时间日期上面处理更复杂的内容,还可以借助 NSCalendar 类丰富我们的处理:
比较日期,可以直接使用如下方法:
从上面看,OC 中很多方法都是很长很长的,并且将每一个参数代表的意思也表示出来了,不会出现错误对应的情况。
NSURL
写前端久了会慢慢觉得 URL 就是一条线上的链接 H5 地址,其实不然,URL(Uniform Resource Locator)中文意思是统一资源定位符,除了 http 协议之外,还有https/ftp/file
协议用来访问一个资源。
在 OC 中,操作 URL 时候应该用专用的 NSURL 类,而不建议把 URL 当做字符串来手工解析。
随着后面的升级 ,原来在 OS 中很多文件输入输出的地方也开始使用 NSURL 了,也即慢慢地将网络当时 OS 中的一部分了。
NSNumber \ NSValue \ NSNULL 包裹类
Cocoa Fundation 框架的集合类(NSArray\NSDictionary\NSset)中只可以放入对象,前端同学可能开始时候会很不适应,假如想放入 int\float\double\bool 等基础类型,需要将其包裹成 OC 对象在进行放入,这里就需要使用 NSNumber 包裹类了,才能间接的将基础类型放入。
但是对于结构体、指针这种复杂的数据类型,NSNumber 也无法包裹,这里需要使用 NSValue 类,它是 NSNumber 的父类,可以将任意类型包装成对象。
前面的数组字典中是不能自己放入nil
的,因为在里面有结束
的含义,但是有时候我们又确实需要一个特殊的对象来表示空值,这里就需要 NSNULL 了,可以通过类方法 +(NSNull *)null
来定义,同时可以通过if(obj==[NSNull null])
来判断是否为 NSNull。
实际开发中极少使用 NSNull,而且一般习惯也不会单独判断这个(默认大家都不用),所以用它也会很危险(大多数情况是用 nil,nil 可以接任何消息,但 NSNull 不行,二者特性的区别可能引起 crash)。
小结
通过以上文章,最多只能够让大家对 OC 编程有一些了解,谈不上深入,更多的是希望前端对于 H5/Weex 的深入了解和优化不要局限到最上面薄薄的一层,完全可以联系到底层的加载、渲染、图片库、网络库等等来进行优化。
从语言层面来说,OC 和 JS 还是挺有意思的,变量/方法命名的风格正好相反,苹果更加鼓励开发者程序命名尽量使用英文全称并且是尽可能详细,通过看到方法和变量就知道是做啥的,看写得好的 iOS 仿佛看散文一样,譬如 -(NSArray *) componentsSeparatedByString:(NSString )separator; 分割字符串,在 JS 里面直接通过 str.split() 就解决了,更多前端开发者习惯不长的命名,因为需要从网络下载,尽管压缩工具会做,但大家也习惯短命名来表示。 由于编译型语言缘故,写 OC 过程中很多错误可以在编译过程就发现,同时运行速度快,同时很多事情苹果都帮开发者做了,包括工程体系,这样其实写 iOS 可发挥的地方没有前端多;反之 JS 为解释性,性能更多依赖于引擎,加上为语言动态,写起来也爽,很多奇淫技巧可使用,加上 Node 的发展,让其可以做很多有趣事情。
各有优点,喜欢 Web 的快速和开放,也爱 iOS 的优雅体验和统一化。