| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
jopen
8年前发布

从前端到iOS

引子

我从去年3月份开始学习 iOS,大约1个多月之后进入正式开发,截止目前已经完成了4个 App(两个公司的中型 App,两个私人的小型 App)

陆续有一些做前端的同事向我咨询该如何入门 iOS 开发,所以最近回顾了一下学习的历程,写成本文。

这篇文章不是 Step by Step 的介绍,也不会深入讨论太多技术细节,而主要是提炼关键的知识点,并将 iOS 与前端做一些类比,希望帮助前端开发者「触类旁通」「举一反三」地快速了解整个 iOS 体系,以更针对和有效地学习。

另外我推荐在入门阶段,不要去深究一些过于细节和深入的知识或者概念,否则很容易打消学习热情(就像我不会推荐在前端入门阶段就去研究派生继承一样),这在文章中会陆续有提到。

在阅读之前,我希望你至少拥有以下技能:

  1. 非常熟悉前端的知识体系,JS,HTML,CSS,DOM,BOM 这些概念应该了然于胸
  2. 使用过 Backbone,Angular, React 等框架中的任一,也就是说至少做过 SPA,思考过 MV*

修改历史

由于我也是初学 iOS 不久,为了校正文章中的错漏,预留一小节

  • 2016-01-15 First Blood

准备工作

首先,做好心理准备。iOS的体系非常庞大,所以需要投入大量时间和精力。你最好能找到一个非常坚实的理由来做支撑。

比如「 iOS 开发的薪水好高丫我一定要学会然后跳槽挣更多钱」就非常不错,当然这种理由可能会受到 外部环境 影响,所以找一个内因会更好。

例如我学习 iOS 的理由是「 仅靠前端技术难以满足移动端的用户需求或体验要求 」。去年女儿刚出生,为了记录喂奶的时间,我尝试过触屏页面,可惜体验上确实难以与 App 相比,那么作为一名以创造更好用户体验为工作目的的程序员,我实在找不到不学习一门移动端开发技术的理由。

其次,做好硬件准备。买一台 Mac 设备,穷人可以选最低配的 Air (5K+) 或者 Mac mini (3K+),机器性能亲测够用(对的我就是穷人T_T),别折腾黑苹果或者虚拟机,把时间用在刀刃上。iPhone 或者 iTouch 可以晚点再买,因为如果只是出于学习目的,前期使用模拟器就够了。

最后,准备好学习资料,比如书籍、视频、PPT 等等。不要惊讶,我前面说过,这篇文章只是给你「指路」用的,请配合其他详细的资料一起学习。

鉴于市面上这些资料相当多,我时间有限难以一一辨别,出于不误人子弟(以及没广告费)的考虑,就只推荐两个吧:Google 和 iOS官方文档库

知识点介绍

如果是第一次打开 iOS 的官方文档,估计会被这密密麻麻的链接直接打消掉学习热情。请坚持住!下面会逐一介绍基础的概念,帮助你先建立模糊(不一定准确)但整体的认识。

开发语言

iOS 的开发语言有两种:Objective C 和 Swift,应该学习哪个呢?在当前(2016.01),我依然推荐先学习 Objective C,主要理由是:

  1. 各种轮子、可参考的示例、问题的答案,OC 更多一些
  2. 只会 Swift 不一定能立即参与公司的项目,或者找到一份 iOS 开发工作,因为正式使用 Swfit 的公司或者产品比例不高
  3. 与前端学习一样,语言只占小部分(ECMAScript 标准不包含 DOM/BOM 等大部头),所以别在这里太纠结了,而且对较有经验的开发者,换一种语言并不是难事。

我推荐入门时别在这个部分停留太多时间,尽快进入到界面开发去寻找成就感(语言癖请无视)。Code School 的 Try Objective-C 还不错,花一晚上时间就可以做完,再配合经常查询 Foundation 框架的文档 ,基本够用。

下面罗列一下 OC 语法的大致内容:

  1. OC 是 C 的超集,开发中会使用到 C 的控制语法(if/for/while)、变量类型(如数值 int/float/double )、指针等,建议翻出大学的 C 语言课本稍微回忆下
  2. OC 是面向对象的,刚才提到的 Foundation 框架提供了基本的类型,比如 NSObject/NSString/NSArray/NSDictionary,建议常去文档翻翻后3个类的 API,比如 stringByReplacingOccurrencesOfString:withString: (@_@)
  3. Foundation 有 NSNumber 这样的「数值」类,但却不能直接使用+-*/等运算符,所以在计算部分还是会用 C 的数值类型,或者 NSInteger/CGFloat 等(推荐后者),但是注意 NSInteger 不是类,而只是 int 或 long 的宏定义(根据 CPU 是32位或64位)
  4. 别觉得 OC 古老,它有 Block 能玩函数式,还有 Category 语法能玩元编程,入门阶段可以了解下,后面再深究
  5. OC 没有垃圾回收,内存管理有 MRC 与 ARC (默认)两种方式,实际上原理基本一样,不过 ARC 可以省略很多代码(半自动),使用 ARC 时简单的代码(比如入门时写的练习)都不用特意去关注内存问题,建议在入门时了解下引用计数的基本原理和 strong/weak 等 property 修饰符,入门之后有时间再慢慢细读「iOS与OS X多线程和内存管理 」一书(看睡着过逃……)

在习惯了话唠式的 API (componentWillReceiveProps 算什么)以及满眼奇怪的 @ 和 [] 之后,赶紧进入下一节

界面构建方式

在前端,我们通常使用 HTML+CSS 这种声明式的语言来构建界面,而在 iOS 里有两种方式

  1. 纯代码手写,类似于使用 JS 创建元素、appendChild 这样来一步步构建界面
  2. 使用 Storyboard/Xib 这种可视化方案,类似于 VB/C# 里的拖拽控件,比 HTML+CSS 还要方便

关于到底哪种方式好,一直争论不休,比如可以看看 唐巧的这篇文章

我的观点是:

  1. 目前不推荐 Storyboard , 这种技术可以将整个 App 的界面全用一个文件来描述,虽然很方便也很直观(可以一眼看明白 App 的界面结构和关系),但是多人维护时文件非常容易冲突而且难以解决(Apple 挖的坑),而且再加上这个技术诞生的晚,使用它的公司和产品也不多
  2. 推荐 Xib,虽然也容易冲突,但是因为是一个界面一个 Xib 文件,所以概率不高,通过 Xib 可以直观的看出单个界面的元素组成,拖拽的方式也很方便
  3. 同样推荐使用代码手写,首先是采用这样方式的公司不少,其次手写也有不少好处,比如不会冲突、易于复用代码等等

注意,目前苹果官方的文档和示例里,基本都是用 Storyboard(毕竟是主推的新技术),建议先跳过这些部分。另外一个思考,为啥前端没人争论类似问题呢?

界面元素

我们先粗略地看一下前端界面是如何组成的:

  1. 基本的界面单元是元素(Element),它有很多种类型,如 div/span,有些还自带交互如 a/input/select
  2. HTML 声明元素(Element)及元素的层次关系
  3. CSS 负责元素的样式与布局
  4. 要构造新的控件,需要组合已有的元素(比如日期选择器),但是在 WebComponents 等技术出现之前复用比较麻烦(组件化是前端目前的热点)

下面来对比看一下 iOS 的情况

  1. 基本的元素是 UIView,有很多子类(是相当多),如 UIButton/UILabel/UIImageView 等等,这些都定义在 UIKit 框架中,建议多翻翻 UIKit 文档
  2. 使用 Xib 声明 UIView 的结构或者直接用代码来组合(addSubview等方法)
  3. 没有 CSS,可以使用控件属性控制样式,比如背景、字号、颜色等,但远不如 CSS 强大,布局后面再提
  4. 构造新的控件,可以通过继承已有控件的方式来实现,复用方便

可以看到不少概念还是相通的,可惜没有 CSS(做 iOS 开发时真挺想念它的)

MVC 与界面显示

下面要提一些 iOS 中特有的概念和知识,先看一张图

图中提到了两个概念:UIWindow 和 ViewController

  1. UIWindow 代表窗口,通常 App 里只有一个窗口(跟前端很像)
  2. 要显示界面,首先要指定 UIWindow 的 rootViewController 属性,也就是一个 ViewController 对象,ViewController 的主要作用是管理和展示 UIView 以及响应用户交互
  3. 然后指定 ViewController 的 view 属性,也就是 UIView 对象
  4. 最后这个 UIView 会显示在屏幕上

如果你用过一些 MV* 类的框架,应该对 Controller 的概念不陌生,而比前端更进一步的是, Apple 直接在开发库中内置了 MVC,建议阅读 Apple 官方的 MVC 介绍

这里要提一个 iOS 中特有的重要概念: delegate ,ViewController 就是 UIView 的 delegate,以 UITableView 为例,它的数据来源(有多少 Cell、每个 Cell 长啥样),用户交互(选择一个 Cell)以及生命周期都是委托给对应的 ViewController 处理,建议好好研究下 UITableViewController 的用法,毕竟这是 iOS 开发中使用频率最高的类,而且完整展示了 MVC 的协作方式。

理解了上面的概念,可以再看看稍微复杂的 App 结构

通常 App 会有多个页面,每个页面都会由一个 Controller 进行管理

这些 Controller 可以形成一个类似堆栈的结构,栈顶 Controller 的 view 才会显示

怎么压栈呢?所有的 Controller 都有 presentViewController 方法,可以用来显示一个 Modal 页面;UINavigationController (带导航栏的 Controller)的 pushViewController 方法也可以

好了,现在再按从大到小,由根到叶的顺序总结一下关于界面的知识

  1. iOS 内置了 MVC 的支持,提供了 ViewController 的概念,我们沟通中常说一个 App 页面,通常指的就是一个 ViewController 对应的界面,这是原生前端所没有的更抽象的概念
  2. 页面的切换,可以通过修改 ViewController 的堆栈来实现(不准确,比如 Tab 不是,但不影响理解)
  3. App 显示的「根」是 UIWindow 的 rootViewController 的 view
  4. 根 View 下可以有多个层级、各个种类的子 UIView,他们共同组成了当前界面

事件响应

iOS 的事件响应原理比前端略复杂一些,我先说入门,再细谈原理

入门阶段,你只要学会 Target-Action 即可,基本能满足简单的交互要求

  • 如果使用 Xib/Storyboard,直接拖拽添加 IBAction 方法即可
  • 如果纯代码,那么需要调用控件的 addTarget:action:forControlEvents: 方法

这两种方式是等价的,与前端 addEventListenter 的方式也很类似

不过你会发现,很多控件是没有 addTarget:action:forControlEvents: 方法的(比如 UIImageView),因为这个方法源自 UIControl,真正的继承结构其实是这样的: UIButton < UIControl < UIView

那如何为 UIImageView 之类的控件添加触摸事件呢?可以使用 UIGestureRecognizer,请看最常用的 UITapGestureRecognizer 子类

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imgTapped:)];   [imgView addGestureRecognizer:tapRecognizer];  imgView.userInteractionEnabled = YES;  // 对于 UIImageView 默认是 NO

可以从 UIGestureRecognizer 的文档中发现更多的子类,涵盖了各种常见手势,比如 Tap/Pinch/Swipe 等等。相比于前端还需要自己通过组合 TouchUp/TouchMove 之类的原始事件来实现手势,iOS 显得方便的多。

学会以上两种方式就能解决很多问题了,不过内在的原理是怎样的呢?有没有类似事件冒泡的机制呢?UITapGestureRecognizer 与 UIControlEventTouchUpInside 有没有关系呢?

想要搞懂这些问题,我推荐仔细阅读这几篇文档: Event Delivery: The Responder Chain , Gesture Recognizers

下面我对原理的简单总结:

  1. 用户触摸开始/移动/结束,都会产生 UITouch 事件
  2. 系统会首先寻找事件对应的 UIView,方法是从外向里通过 hit-test 链 (类似捕获)寻找
  3. 找到对应的 UIView 之后,会根据事件的阶段调用相应方法,如 touchesBegan:withEvent:,方法内如果调用了 super,那么系统会寻找 nextResponder,通常是父 View 或者其对应的 ViewController,再调用相应的 touches 处理方法,这就是从内向外的 Responder 链 (类似冒泡)
  4. 如果 UIView 没有调用 super,那么事件不再继续传递(类似 stopPropagation)
  5. UIGestureRecognizer 与 UIControl 实际上是对上述机制的更高级封装(手势事件),例如从 UIControlEventTouchUpInside 的名字就可以大概推测出,他其实通过组合 TouchBegin 和 TouchEnd 来封装出的事件(像不像 Zepto 里的 tap 事件封装?不过 iOS 这是内置的)
  6. 为 UIView 添加了 UIGestureRecognizer 之后,UITouch 事件会交给 UIGestureRecognizer,而不再交给 UIView,因此添加了 UITapGestureRecognizer 之后,UIButton 的 UIControlEventTouchUpInside 就不会触发了

布局技术

CSS 的布局规则其实非常复杂,这里不赘述了,iOS 是什么情况呢?我按照历史的顺序来梳理下先明确下,iOS 坐标系的概念与前端一致,都是左上角为原点,而且基本单位 pt 与前端 px 一样,都是指逻辑像素而非物理像素(页面无缩放时)

  1. 很早很早之前,由于屏幕只有一种规格,所以直接采用绝对定位就行了,比如常见的 initWithFrame: 其实就是指定了元素的大小和绝对位置
  2. 后来 iPhone 支持了横屏以及 iPad 出现,苹果推出了 Autoresizing,可以根据设置的规则自动缩放定位元素,举个例子,通过设置简单的规则,可以让一个控件在 iPhone4s 和 iPhone6P 下占据屏幕的比例一样(按屏幕大小缩放),不少产品依然在使用这种技术
  3. 后来苹果又推出了更强大的 Auto Layout,通过指定元素自身或之间的约束,来控制布局与元素大小(CSS 里似乎完全没有这样的布局方式),举个例子,通过 Auto Layout,可以让两个控件之间的水平间距在任何屏幕尺寸下都一致,而使用 Autoresizing 就做不到
  4. iOS8 又引入了 Size Classes ,它与 Auto Layout 并不冲突,而是在更抽象更高层的角度考虑布局布局问题,如果你的应用需要考虑横竖屏或者跨 iPad+iPhone,那么一定要好好研究它

由于现在 iPhone 的尺寸已经多达4种,因此 Auto Layout 非常重要,建议重点学习

除了看 官方的文档 之外,我也简单梳理下 AutoLayout 的原理:

  • 使用约束(Constraint)来描述元素与元素,或者元素自身的位置大小
  • 一个约束其实可以简写成这么一个方程:A.属性值 = B.属性值 * multiplier + constant,例如我们期望一个元素 A 左侧距离父元素左侧边界 10 pt,那么约束是这样的 A.left = SuperView.left * 1 + 0
  • 属性值包括:left,top,right,bottom,centerX,centerY,width,height,为了照顾文字从右往左写的阿拉伯人,还有两个属性 leading 和 trailing,根据文字书写方向来决定究竟是左还是右(多语言方案)
  • 布局时,系统就是在求解多元一次方程组(约束就是方程),如果能正确解出所有的元,那么就能正确布局

举个例子,我们期望一个矩形左右各距离屏幕边缘10pt,高度固定为100pt,顶部距离屏幕 20pt,那么我们需要添加这么几条约束:

  1. 矩形.top = SuperView.top * 1 + 20
  2. 矩形.left = SuperView.left * 1 + 10
  3. 矩形.centerX = SuperView.centerX * 1 + 0
  4. 矩形.height = 100

根据这4个方程,加上初始条件(SuperView 的 top,left 都是0,centerX 为屏幕宽度一半),可以求解出矩形的 left,top,width,height,那么矩形的布局就确定了

再一个稍微复杂点的例子,我们期望矩形 A 和 B 能够左右等分屏幕,那么约束是这样的

  1. A.left = SuperView.left * 0 + 0
  2. B.left = A.right * 1 + 0
  3. A.top = SuperView.top * 1 + 0
  4. B.top = SuperView.top * 1 + 0
  5. A.width = B.width * 1 + 0
  6. A.height = SuperView.height * 1 + 0
  7. B.height = SuperView.height * 1 + 0
  8. B.right = SuperView.right * 1 + 0

根据以上8个方程,可以求解出矩形 A 和 B 的一共 8 个属性。当然,这样的结果还有其他等价的约束方程组

AutoLayout 的约束,可以在 Xib/Storyboard 中添加(添加后还可以拖出 IBOutlet 哦),也可以用代码手写,如果你选择后者的话,可以试试 Masonry 这个库

包管理

OC 像早期 JS 一样,没有内置包管理,所以有人用 Ruby 开发了一个第三方的包管理系统 CocoaPods ,使用方式请看文档,我列一下国内镜像的安装命令

# 从国内 Rubygems 镜像安装 Cocoapods  gem sources -r https://rubygems.org/  gem sources -a https://ruby.taobao.org/  sudo gem install cocoapods    # 指定 Pod 国内镜像  pod repo add master https://gitcafe.com/akuandev/Specs.git

指定 Pod 国内镜像可能会很慢,可以去~/.cocoapods 目录下执行 du -sh * 查看目录大小来判断进度,目前执行完毕是400多M

深入 iOS

入门之后,该继续学习和深入哪些方面呢?我觉得以下几个方面是非常重要的,不过既然本文不会探讨深入的技术细节,那么我就主要列举下关键词

  1. 内存管理:这可能是用惯了带 GC 语言的人最讨厌的,不过这个坎是绕不过去的,前面提到的「iOS与OS X多线程和内存管理 」前半部分请好好阅读
  2. 多线程:用惯了单线程 JS 的同学又要哭了,好吧,这也是绕不过去的,关键词 GCD/NSOperationQueue,好好研究吧,上面提到那本书的后半部分,也可以好好读一读
  3. 本地存储,简单的 NSUserDefaults(可以类比于 LocalStorage)真的很简单,复杂的如 CoreData 真的很复杂
  4. 兼容性,iOS 开发也有兼容性问题,比如一些技术或者 API 是 iOS 新版本引入的,那么如果你要支持旧版本就不能使用,另外内置框架比如 UIKit 的内部实现可能在某个版本做了调整,那么某些代码也许就会有问题,但是比之前端还是简单很多
  5. 交互,iOS 的交互可是有非常完备体系的,建议阅读 iOS Human Interface Guidelines 中文译本 ,读完你会有收获的,而且我觉得做移动前端的开发者,也应该好好读读
  6. 与 Apple 打交道,例如证书、签名、打包、提交审核、发布等等杂事,这块麻烦的让人抓狂,幸亏有人正在整理了 iOS 开发流程

结尾

这是我写的最长的一篇文章,如果你坚持看到了这里……祝阅读愉快,学习顺利,以及世界和平……

</div>

来自: http://chaoskeh.com/blog/learn-ios-from-frontend.html

 本文由用户 jopen 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1452844984730.html
iOS开发 移动开发