写给前端看的 iOS 梳理(上)

去年双十一为了排查一些 Weex 性能问题开始接触 iOS 相关学习,恰逢今年 1 月份开始慢慢参与 iOS 业务开发,借此机会整理一下 iOS 开发中的一些基础知识,用于备忘,同时旨在通过系列文章让前端同学在日后碰到 iOS 的代码可以看懂,方便更好的理解端上的一些原理。

大纲

文件格式

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,是 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:

//NSDate 转 NSString

NSDate *now = [NSDate date];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";

NSString *str = [formatter stringFromDate:now];

NSLog(@"%@", str);

// NSString 转 NSDate

NSString *str = @"2018-02-08 11:53:12";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";

NSDate *date = [formatter dateFromString:str];

NSLog(@"%@", date);

假如想在时间日期上面处理更复杂的内容,还可以借助 NSCalendar 类丰富我们的处理:

NSDate *date = [NSDate date];

NSCalendar *calendar = [NSCalendar currentCalendar];

// 利用日历对象获取年月日时分秒

NSCalendarUnit type = NSCalendarUnitYear

| NSCalendarUnitMonth

| NSCalendarUnitDay

| NSCalendarUnitHour

| NSCalendarUnitMinute

| NSCalendarUnitSecond;

// cmps 包括 year、month、day、hour、minute、second 属性

NSDateComponents *cmps = [calendar components:type fromDate:date];

比较日期,可以直接使用如下方法:

- (NSDateComponents *)components:(NSCalendarUnit)unitFlags

fromDate:(NSDate *)startingDate

toDate:(NSDate *)resultDate

options:(NSCalendarOptions)opts;

从上面看,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 对象型

@10;

@10.5;

@YES;

@(num);

// NSNumber 类提取基础型

- (char)charValue;

- (int)intValue;

- (double)doubleValue;

- (BOOL)boolValue;

但是对于结构体、指针这种复杂的数据类型,NSNumber 也无法包裹,这里需要使用 NSValue 类,它是 NSNumber 的父类,可以将任意类型包装成对象。

// 结构体包裹,譬如 NSPoint、NSSize、NSRect

- (NSValue *)valueWithPoint:(NSPoint)point;

//从 NSValue 对象取出之前包装的结构体

- (NSPoint)pointValue;

前面的数组字典中是不能自己放入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 的优雅体验和统一化

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180210B122RT00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券