包含一些自我的想法,与熟悉的java语言的比较,项目的进化旅程等.
内存管理
对c语言来说,内存需要手动分配与释放,因此在objc里也类似.
在objc里,内存管理主要靠retain count
(引用计数),在alloc
,retain
,copy
时会加1,在release
时会减1.
问题是什么?
内存管理主要有两个问题:
- 释放正在使用的对象: 程序崩溃
- 未释放不再使用的对象: 内存泄露
规则是什么?
内存管理的规则也很简单:
- 我们拥有创建的对象,不再使用时必须进行释放
- retain后不再使用时也必须release
- 不释放非自己拥有的对象
为了加深理解,举个例子,新建一个NSURLConnection连接,但是请求是异步返回的,那什么时候释放呢? 很简单,NSURLConnection对象用完就释放,它会在发送请求时将自己retain一次,请求返回时又会自动release一次. 因此你不用理它,管好自己就行,用完就释放.
ARC(Automic Reference Counting)
新版本的objc引入了ARC,管理内存的自动释放(对应的是MRC).
要注意的是这个是在编译
时期(而非运行时期)自动在代码中插入合适的内存管理代码(类似插入retain,release,autorelease吧).
此外在运行期也会有一些优化.
项目文件结构
目标:
- 目录结构清晰
- 快速找到文件
- 减少依赖,增加可移植性
基本概念:
- 主要的项目功能: 外层先按
功能模块
分,内层再按MVC
分. - 工具类等功能: 单独的目录.
- 模块内可以包含子模块,但建议层次不超过三级.
具体结构设计:
Class
: 存放所有模块功能Base
: 存放基类Vendor
: 第三方(主要的第三方用cocoapods,小的放这里)Framework
: 类库Resource
: 存放资源Support
: 工具类,分类,宏定义,PCH文件等Main
: AppDelegate相关
XCode项目结构
- Workspace: 就是工作空间,里面可以包含多个项目,为什么?比如这些项目间有关联.
- Project: 项目的意思(这才是主体),包含构建一个或多个软件产品所需的所有文件,资源和信息
- Target: 指定要构建的产品,并包含构建需要的文件说明.target之间可以互相独立或依赖.
- Project: 项目的意思(这才是主体),包含构建一个或多个软件产品所需的所有文件,资源和信息
- Scheme: 定义可构建的Target以及构建时使用的构建信息
在Project Navigator
中,选择项目,右侧会展示Project Editor
,这里可以看到所有的Target.
此外,可以看到产品信息和构建配置(Build Settings),其中构建配置内的大部分配置项还区分Debug
与Release
.
Debug就是多输出一些调试信息,Release会进行代码优化.
关于Workspace的作用,可以拿Cocospods举例,
当使用Cocospods来管理第三方时,会自动新建一个跟原项目平行的Pods项目,里面放置第三方依赖.
原先打开的是一个名为app.xcodeproj
的项目
,现在改为打开cocospods自动生成的名为app.xcworkspace
的工作空间
,
工作空间里有原来的项目,与放置第三方依赖的Pods项目.
Target使用场景?
- 用来区分免费版与收费版,主体上功能差不多,一些地方有区别.
- 用来区分开发与生产环境
- 用来区分ios与ipad?
Scheme使用场景?
- 打测试包与正式包
XCode界面开发
Interface Builder
XCode中编辑界面的工具叫Interface Builder
,关于这个工具:
之前是个独立软件,创建的文件是二进制格式nib.
后来集成到XCode内,为了方便版本控制,创建的文件是xib(xml文件格式),
在工程编译的时候再转为nib格式.
方式
界面开发主要有以下几种方式:
- 代码: 复杂的大项目推荐使用这种方式
- 缺点:
- 不直观,没法所见即所得,只能写完,然后运行才能看到效果
- xib
- storyboard(最新&官方推荐): 类似xib的集合,每个xib对应一个场景,可以设置场景关系(表现为一些连线)
- IBOutlet: 就是引用了,让代码可以操控界面元素(它会解析为nothing,仅作为与界面相关的标记,如
IBOutlet UILabel *title;
) - IBAction: 比如点击按钮执行相应的方法(它会解析为void,同时也作为与界面相关的标记,如
- (IBAction)ok:(id)sender;
) - segue: 页面跳转方式(奇怪的名字)
这是什么鬼?花了我好多时间研究. 首先它是名为
UIStoryboardSegue
的类,里面有id,来源UIViewController,目标UIViewController这几个字段,还有个perform
方法.这就有些明了了,执行一个segue其实就是调用一下perform方法,然后在来源与目标ViewController之间做点操作而已,比如跳转,返回. - IBOutlet: 就是引用了,让代码可以操控界面元素(它会解析为nothing,仅作为与界面相关的标记,如
- 缺点(继承了xib的所有缺点- -!):
- 打开比较慢(因为多个场景同时展示)
- 屏幕小时,编辑起来很挤
- 多人编辑时,合并容易冲突: 因此实际工作中,一个storyboard最好只由一个人负责
吐槽: IBOutlet与IBAction的用法真奇葩,还不一样…两个都有标记的作用,标识着可以与界面产生交互(连线),但IBAction竟然代替了void的位置.
triggered segue/presenting segue
- triggered segue: 就是用来触发segue的
- presenting segue: 就是用来接受触发的
(明白这两种的区别,segue就很简单明了了)
自动/手动的segue
- 自动型的segue: 比如从按钮直接拖线到另一个ViewController,action选择show,这样点击按钮就会跳转页面.自动型的没法加条件判断哦,要加可以使用手动的.
- 手动型的segue: 在ViewController上右键,最上方的manual连线到另一个ViewController,action比如选择show.那么怎么触发这个segue呢?先选中这个,在
Attributes inspector
中设置identifier,然后比如点击按钮执行方法,在方法内使用[self performSegueWithIdentifier:@"id" sender:nil];
即可手动执行segue了
segue类型
- modal(iphone&ipad): 最常用的,新的场景覆盖旧的,必须先关闭这个场景才能与上个场景交互
- push(iphone&ipad): 这种一般需要第一个界面是
Navigation Controller
,下一级使用那种右侧划入的方式 - custom(iphone&ipad): 自定义方式
- popover(ipad): 浮窗形式
- replace(ipad): 替换当前scene,经常用在ipad的特殊视图上(spit-view)
- unwind segue(或叫exit segue): 简单说就是返回,从页面A返回到页面B,连线时需要指定一个方法
- (IBAction) unwindToThisViewController:(UIStoryboardSegue *) segue
,这个方法写在B内(方法名随意). 执行这个segue时(如按钮或代码调用),就会执行这个方法并返回到B(执行方法在segue的perform前).
segue跳转代码
//根据 segue Identifier跳转界面
[self performSegueWithIdentifier:@"GotoTwo" sender:self];
//以modal 方式跳转
[self presentModalViewController:nil animated:YES];
// 以 modal跳转的返回方法
[self dismissModalViewControllerAnimated:YES];
//压进一个viewcontroller
[self.navigationController pushViewController:nil animated:YES];
//弹出一个viewcontroller 相当与返回上一个界面
[self.navigationController popViewControllerAnimated:YES];
比较如下
代码 | xib | storyboard | |
---|---|---|---|
复用性 | 高 | 中 | 低 |
批量处理 | 高 | 低 | 低 |
布局
- frame
- Autolayout(推荐)
- 缺点:
- 没有占位符,一些界面需要使用看不见的view来占位
- 某些常见的界面布局难以表述,如等间距
- 需要设置很多约束,比较繁琐
- 需要根据约束去求解位置,某些场合下比较耗时
Size Class
按照View的尺寸大小分成几个类型,然后在xib/storyboard中根据类型设置不同约束.
设备宽高区分为Compact
和Regular
,不区分为Any
.
所有设备的Size Class都是预先固定定义好的,比如iphone6竖屏时wC hR
(w表示width,h表示height,C表示Compact,R表示Regular),ipad不管竖屏还是横屏都是wR hR
Safe Area
用来避免内容被状态栏,导航栏,标签栏等覆盖.
IOS11前用的是topLayoutGuide
与bottomLayoutGuide
,IOS11开始用safeAreaLayoutGuide
代替.
推荐不要把内容放到Safe Area外.
First Responder & Exit
First Responder
指任意对象在任意时间具有第一响应状态的代理对象.
比如某个输入框是First Responder时,按下按钮,给First Responder也就是输入框发送剪切的命令.
网上说实际用的不多.
Exit
就是用来连线unwind segue的,看上面.
MVC
- Controller直接引用View与Model
- View与Controller通信:
- 设置View对应的Action Target,如设置 UIButton 的 Touch up inside 的 Action Target
- 设置View的delegate,如UIAlertViewDelegate
- 设置View的data source,如UITableViewDataSource
- Model与Controller通信:
- Notification
- KVO
其它问题
为什么字符串前要用@
?
因为Objc与C语言兼容,如果不加,那么字符串会被编译器当作C语言的字符串. 那为什么不直接用C的字符串呢?因为NSString好用,方法多呗.
数字也是类似的道理.