iOS 实战开发课程笔记
本贴旨在作为对极客班 《iOS 开发实战》第五期期课程视频重新学习的笔记。
目标是建立一个比较完整的 iOS 开发知识点框架以及快速手册,我想找工作……所以,打结实点基础,你们懂的。
对各个内容的详细研究会在学习完毕后开启新贴深入探究。
简书我不知道怎么添加目录,所以我觉得也许在网易上看会更清晰点……篇幅过长。
这是我的网易博客账号,欢迎各位同学吐槽。
http://blog.csdn.net/mubinhuang/article/details/50649650
该贴仍在不断完善中。
0 导论
0.1 技术支持
0.1.1 苹果技术支持
- 技术文档打开方式 <br />Xcode软件 -> Help -> Documentation and API Reference<br />文档是在网上读取的,如果想要更加快速,可以先进行下载。旧版本的模拟器也在这里安装。 <br />Xcode -> Preferences -> Downloads
- 开发者社区 https://developer.apple.com
- iOS文档库 https://developer.apple.com/library/prerelease/ios/navigation/
- WWDC 视频
0.1.2 其他技术支持
- stack overflow 社区
- OurCode 社区
- Cocoa China 社区
- V2EX 社区
- GitHub (建议查看学习 awesome iOS 系列)
0.2 学习方法
0.2.1 方法
- 认真看视频。
- 整理笔记。
- 完成练习示例。
0.2.2 参考书
- ios 9 programming fundamentals with swift
- ios 7 programming fundamentals (Objective-C)
0.2.3 App Programming Guide for
- 界面基础
View Controller Programming Guide
View Controller Catalog
View Programming Guide
UIKit User Interface Catalog
Event Handing Guide
- 图形和动画
Drawing and Printing Guide
Concurrency Programming Guide
Quartz 2D Programming Guide
Core Animation Programming Guide
- 网络与存储
Network & Internet Starting Point (知道个方向)
Networking Overview (了解个概念)
Data Management Starting Point (知道个方向)
- 其他
Auto Layout Guide
Scroll View Programming Guide
Table View Programming Guide
Collection View Programming Guide
<br />
1 Hello Word
1.1 创建新工程
- Create a new Xcode project
- File -> New -> Project [shift + command + N]
1.2 选择工程模板
可以选择多种多样的工程模板,包括 iOS, OS X, watchOS, tvOS 一般选择 iOS -> Single View Application。
1.3 工程信息
- Project Name:产品名称
- Organization Name:组织名称
- Organization Identifier:新产品唯一名,一般把公司域名反过来写。
- Language:运行语言
- Devices:运行设备(通用,iPhone,iPad)
- Use Core Data:是否使用数据存储
- Include Unit Tests:测试模块
- Include UI Tests:UI测试模块
1.4 Git 仓库
版本控制
Source Control:Create Git repository on My Mac
后续版本控制有专门篇幅。
1.5 Xcode界面了解
1.6 Storyboard
- 图层识别
选中图层之后,可以在 libraries -> identity inspector -> Document -> Label 中设置图层名称,可以更改图层在 Storyboard 的 Document Outline 中的名称。以方便识别。 - 组件 library
可以拖动这里的各种组件到 canves 或其中对应的图层上。 - 设置 Document Outline 显示名称
选中组件 -> Indentity inspector -> Document -> Label - 设置 ViewController 尺寸
选中 ViewController -> Attributes inspector -> Simulated Merices -> Size
1.7 模拟器
- 显示尺寸调节
Window -> Scale -> … [command + 1-5] - 设备操作
Hardware -> … - 返回出厂设置
Simulator -> Reset content and Settings…
1.8 真机调试
- 添加调试账号
Xcode -> Preferences -> Accounts -> + - 设置调试账号
Workspace -> General -> Identity -> Team 进行选择 -> Fix issues - 运行
首次运行会提示错误,需要真机验证
真机 -> 设置 -> 通用 -> 描述文件 -> 选中信任 -> 回到 Xcode 再次运行
1.9 App 基本概念
- iOS App 代码结构(这是 Objective-c 语言,Swift 有所不同,main 文件会被隐藏)
- main()
- UIApplicationMain()(生成一个 UIApplication 对象并设置成为该应用的代理。)
- UIApplication 对象
- UIApplicationDelegate
- iOS App 运行环境
- Sandbox
- 获取目录 NSHomeDirectory()
- iOS 应用都是一个 Bundle
- Bundle: 带有 Info.plist 字典的目录
- 通过 NSBundle 类访问其中的资源
- 主要是通过 mainBundle
- resource bundle 和 framework(可执行动态库)
- 查看 App Bundle
设置栏中选择设备 -> Generic iOS Device -> command + B 构建 -> Workspace -> Products -> xxx.app -> 右键 查看文件 -> 右键 显示包内容
<br />
3 Button - Storyboard 与代码之间联系方式
介绍最常用的 Interface 组件之一 UIButton,以及它的使用方法。
从而介绍 Outlet Action 等概念。
3.1 UIButton
3.2 IBOutlet
- IBOutlet Connection
把 Nib object 与 代码中的 IBOutlet 变量相连接-
在 Storyboard 中将组件与代码中的 IBOutlet 变量进行连接后,会在 Storyboard 代码中多出来这样一段连接说明
<connections> <outlet property="okLabel" destination="QJt-2z-ban" id="mhJ-Nu-TIR"/> </connections> // property 变量名称 // destination 界面上的组件名称 // id 标志这个连接本身
运行时调用
由于 xib 中存储的是界面模板,所以在允许的时候,类实例代码会触发界面的实例化方法。
最终调用[UINib instantiateWithOwner:options:]
方法实例化界面。
Owner 实际上是调用了一个按名字绑定的属性。[owner setValue:uiObj forKey:outlet.property]
-
其实我自己都看不懂这段在说什么……大概是说 outlet connection 其实是标注了界面与代码之间的关系,然后在程序运行的时候,会通过一系列 runtime 方法调用这种关系,并根据界面模板实例化界面组件,从而生成组件绘制吧。
- Action Connection
-
界面事件连接 IBAction
<connections> <action selector="buttonAction:" destination="BYZ-38-t0r" eventType="touchUpInside" id="BQA-pw-9f8"/> </connections> // selector 方法名称 // eventType 事件类型
-
<br />
4 Image
图片流:界面全部由现成的图片构成。耗内存,但是简便。
代码流:界面全部由代码绘制而成,省内存,适应性高。
4.1 UIImage
-
图片加载
-
图片动画
let anmiationImage = UIImage.animatedImageNamed("ImageArrayName", duration: 2.0) // ImageArrayName 是动画图片的前缀,动画图片资源应该按照该名称后面加数字来命名。 // duration 是总时长。 // KeyNote 可以导出动画的每帧图片。
4.2 Assert Catalog
-
Assert Catalog 介绍
模板会默认生成一个 Assert Catalog 文件并且其中有 Appicon 以用于给 App 提供系统图标。
直接用图片名字的办法加载图片,虽然简便,但是由于这样的做法会把图片缓存在内存中,在图片较多尺寸较大时会照成内存压力。 -
Assert Catalog 功能
添加图片:直接将图片资源拖入 Asset Catalog,或者下面的
+
号。资源属性:每个图片可以有三个尺寸以提供给不同的屏幕尺寸使用。还可以设置适用各种设备和各种特定尺寸 Attributes -> Devices。
-
图片切片:点击图片 -> Attributes -> Slicing -> Slices -> …
-
适用矢量图片
放置对应的图片格式进去 Assert Catalog 之后,然后设置其属性。
-
Attributes -> Devices -> Scale Factors -> Single Vector
<br />
5 第一个 App
5.1 需求分析
- 详细了解应用需求,需要确切了解用户想要的是什么。
- 详细规划应用的逻辑流程,各个模块功能的来由和去向。
5.2 程序设计
平衡设计原则:设计程序时为未来可能的需求做好准备。但是这种办法有好有坏,有时候考虑太多,就会导致当前事情难以完成。如果完全只考虑当前,就可能增加未来重构的次数。中间的度需要靠程序员把握。
- 走通流程图,确认游戏逻辑
- 确认静态数据结构
5.3 示例代码结构
各个代码模块之间的联系和关系的明确。
5.4 Keynote 课件展示
<br />
6 View Controller
6.1 简单的设计模式介绍
6.2 UIViewController
-
UIViewController 介绍
-
获取 ViewController
- 创建 rootViewController
- Info.plist 中的 UIMainStoryboardFile, NSMainNibFile 指定了根控制器的来源。
- UIApplication 会通过调用
_runWithMainScene:transitionContext:completion:
方法。 - 然后调用
_loadMainInterfaceFile
来取出 Info.plist 中 UIMainStoryboardFile 或者 NSMainNibFile 信息。 - 如果是前者,则再调用
_loadMainStoryboardFileNamed:bundle:
。 - 如果是后者,则再调用
_loadMainNibFileNamed:bundle:
。
- 加载好 rootViewController 之后就把这个视图控制器赋值给 appDelegate.window.rootViewController。
- 假如上述方法初始化界面失败,则会调用
UIApplicationDelegate didFinshLaunch
方法来给程序员一个使用程序初始化界面的时机。最开始时,也是只有这一个办法来初始化界面的。 - 如果以上两种办法都没有给
appDelegate.window.rootViewController
赋值,则这个应用的 window 就会为 nil 显示黑屏.
- 创建 rootViewController
-
获取 ViewController 的 View
- 自定义 ViewController 装载过程
- 调用
[UIViewController loadView]
如果有实现,调用之后就不会调用后面的方法了。如果是默认实现则会调用下面的其他方法。 - 调用
[UIViewController nibName]
如果是默认模板,则 nibName 应该是来自 Storyboard。如果是代码调用initWithNibName
则由程序员指定 nib. 如果两者都不是,则会调用下面的方法。 -
[UIViewController exisitingNibNameMatchingClassName:bundle:]
,它会根据 ViewController 方法猜测并且查找 Nib,如果都查找不到,系统会创建一个空白视图。
- 调用
- 要点
- isViewLoaded 判断 ViewController 的 View 是否已经加载好了。
- loadView 中不能调用 super.
- 自定义 ViewController 装载过程
6.3 View Controller Lifecycle
6.3 多个 View Controller
-
弹出新视图的方法
presentViewController:animation:completion:
- UIViewController 的 modalPresentationStyle 是设置弹出控制器风格的属性。
- UIViewController 的 modalTransitionStyle 是设置弹出动画风格的属性。
iOS 8+ 之后新方法
showViewController:sender
释放控制器
dismissViewControllerAnimated:completion:
-
回传数据:把父控制器作为子控制器的代理,通过回调函数来传递数据。并且由父控制器来控制子控制器的释放,而不是子控制器自己调用
dismissViewControllerAnimated:completion:
方法。
<br />
7 Storyboard
Storyboard 也是一个 xib 文件,只是它里面不只是放 View,而是放置 Scene.
可以点击 ViewController 然后直接拖出 Segue 到其他 ViewController 当中,从而创建没有组件触发事件的 Segue。
7.1 Storyboard Segue
-
使用代码进行 Segue 跳转
func segueAction() { // 0 以 Segue 跳转 performSegueWithIdentifier("SegueIdentifier", sender: nil) // 1 获取 ViewController if let nextViewController = storyboard?.instantiateViewControllerWithIdentifier("ViewControllerIdentifier") { showViewController(nextViewController, sender: nil) } }
-
Segue 传值
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // 每次有 Segue 被触发就会调用此函数,以提供传值时机。 }
-
Storyboard Segue 回退
@IBAction override func unwindForSegue(unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) { // @IBAction func unwindFuncName(segueName: UIStoryboardSegue) { } // 名称可以随意,参数至少要有一个 UIStoryboardSegue。用来作为 Storyboard 回退触发事件。 }
7.2 多 Storyboard
-
当场景太多的时候,可以把 Storyboard 分成多个文件。场景之间的过渡,可以通过两种办法实现。
- Storyboard Reference 组件,跟 ViewController 组件一样可以拖动到 Canvas 上。并且可以设置它指向的 Storyboard 文件,Reference ID(如果不指定就是 initial View Controller)。
- 选中需要放置在新 Storyboard 上的 ViewController,然后点击 Editor -> Refactor to Storyboard。然后就会创建新的 Storyboard 文件,并将选中的 ViewController 放置到其中。
-
获取其他 Storyboard
func muchStoryboard() { // 根据名称获取 Storyboard let storyboard = UIStoryboard(name: "StoryboardName", bundle: NSBundle.mainBundle()) }
<br />
8 App Lifecycle
8.1 应用启动
main - 启动程序
UIApplicationMain() - 启动应用代理
UIApplication - 启动消息循环
APPDelegate - 生成应用代理
-
根据 Storyboard 或者代码创建的 ViewController 加载 rootViewController
8.2 用户互动
RunLoop Mode: [source] 其实就是事件源。
main run loop 循环关注事件源。接收事件。
接收到事件就传递给 Application object。
Application object 对事件进行分发。
-
事件根据代码逻辑反馈到视图上。
8.3 AppDelegate
-
出生
-
application:willFinishLaunchingWithOptions:
事件
UI 已经加载出来了。RootViewController 已经创建好,只是还没访问它的 view 方法。
应用级的初始化工作最好都放在这个位置,但是不要在这里做太耗时的事件。
Options 会提供启动状态信息。
App Programming Guide for iOS 文档中的 Preserving Your App’s Visual Appearance Across Launches 中有详细的说明。-
application:didFinishLaunchingWithOptions:
事件
界面已经恢复过了,但是 UI 还没有放置到界面上。这时候代码已经开始执行,但是界面看不见,也不会进行响应。
依然是应用级别的初始化机会。
Options 会提供启动状态信息。
*applicationDidBecomeActive:
事件
应用已经要开始活动了的时机。 -
-
进入不活跃状态
-
applicationWillResignActive:
事件
-
-
进入后台状态
-
applicationDidEnterBackground:
事件
这是一个短暂的时机,默认是 5 秒内完成。但是可以通过beginBackgroundTask
方法可以获取大约 10 分钟的后台运行事件。
如果还需要更长的事件,需要编写后台运行程序。详细查阅文档。
-
-
应用关闭
-
applicationWillTerminate:
事件
如果你的应用刚好被挂起没有多久,然后就被关闭了,就会接收到这个事件。如果你已经被悬挂在后台了,那在关闭的时候就不会收到这个通知。
-
-
应用复活
-
applicationWillEnterForeground:
事件
应用即将回到前台的事件。
-
8.4 移动应用的特点。
移动应用的使用会非常的零散,会在各种状态中来回切换。
<br />
9 Navigation
9.1 Navigation Bar
9.2 UINavigationController
- Navigation Controller 的结构(属性)
- viewControllers (视图控制器数组,管理着导航控制器的所有视图控制器。)
- topViewController (最顶上的视图控制器,绝大多数时候跟 visibleViewController 是同一个,但也不绝对。)
- visibleViewController (当前显示的视图控制器。)
- navigationBar
- toolbar
- delegate
- viewControllers (视图控制器数组,管理着导航控制器的所有视图控制器。)
-
给现有的 ViewController 添加 NavigationController
- 选中 ViewController -> Editor -> Embed In -> Navigation Controller
- 拖动 NavigationController 到 Canvas -> 设置 ViewController 成为其 rootViewController
-
利用 UINavigationController 的 Delegate 方法时机来进行导航时的数据传递(但是尽可能还是用 Segue 方法来进行数据传递)
- navigationController:willShowViewController:animated: (一般数据传递会在这里进行。)
- navigationController:didShowViewController:animated:
9.3 在代码中使用 NavigationController
并不推荐使用代码创建,毕竟用 Storyboard 就很方便了。
setViewControllers:animated:
比较有时机意义,可以让导航不用每次都从 rootViewController 开始。更加灵活。
9.4 自定义导航栏
了解以下各个类的属性,并根据实际要求自定义。
苹果有提供 Customizing UINavigationBar 的代码示例,里面有各种各样的自定义方法。
- UINavigationBar
- UIBarItem
- UIBarButtonItem
- UIToolBar
导航栏标题之上的小字在 Navigation Item -> Prompt 中设置。
<br />
iOS 实战开发课程笔记
本贴旨在作为对极客班 《iOS 开发实战》第五期期课程视频重新学习的笔记。
目标是建立一个比较完整的 iOS 开发知识点框架以及快速手册。
对各个内容的详细研究会开启新贴深入探究。
该贴仍在不断完善中。
0 导论
0.1 技术支持
0.1.1 苹果技术支持
- 技术文档打开方式 <br />Xcode软件 -> Help -> Documentation and API Reference<br />文档是在网上读取的,如果想要更加快速,可以先进行下载。旧版本的模拟器也在这里安装。 <br />Xcode -> Preferences -> Downloads
- 开发者社区 https://developer.apple.com
- iOS文档库 https://developer.apple.com/library/prerelease/ios/navigation/
- WWDC 视频
0.1.2 其他技术支持
- stack overflow 社区
- OurCode 社区
- Cocoa China 社区
- V2EX 社区
- GitHub (建议查看学习 awesome iOS 系列)
0.2 学习方法
0.2.1 方法
- 认真看视频。
- 整理笔记。
- 完成练习示例。
0.2.2 参考书
- ios 9 programming fundamentals with swift
- ios 7 programming fundamentals (Objective-C)
0.2.3 App Programming Guide for
- 界面基础
View Controller Programming Guide
View Controller Catalog
View Programming Guide
UIKit User Interface Catalog
Event Handing Guide
- 图形和动画
Drawing and Printing Guide
Concurrency Programming Guide
Quartz 2D Programming Guide
Core Animation Programming Guide
- 网络与存储
Network & Internet Starting Point (知道个方向)
Networking Overview (了解个概念)
Data Management Starting Point (知道个方向)
- 其他
Auto Layout Guide
Scroll View Programming Guide
Table View Programming Guide
Collection View Programming Guide
<br />
1 Hello Word
1.1 创建新工程
- Create a new Xcode project
- File -> New -> Project [shift + command + N]
1.2 选择工程模板
可以选择多种多样的工程模板,包括 iOS, OS X, watchOS, tvOS 一般选择 iOS -> Single View Application。
1.3 工程信息
- Project Name:产品名称
- Organization Name:组织名称
- Organization Identifier:新产品唯一名,一般把公司域名反过来写。
- Language:运行语言
- Devices:运行设备(通用,iPhone,iPad)
- Use Core Data:是否使用数据存储
- Include Unit Tests:测试模块
- Include UI Tests:UI测试模块
1.4 Git 仓库
版本控制
Source Control:Create Git repository on My Mac
后续版本控制有专门篇幅。
1.5 Xcode界面了解
1.6 Storyboard
- 图层识别
选中图层之后,可以在 libraries -> identity inspector -> Document -> Label 中设置图层名称,可以更改图层在 Storyboard 的 Document Outline 中的名称。以方便识别。 - 组件 library
可以拖动这里的各种组件到 canves 或其中对应的图层上。 - 设置 Document Outline 显示名称
选中组件 -> Indentity inspector -> Document -> Label - 设置 ViewController 尺寸
选中 ViewController -> Attributes inspector -> Simulated Merices -> Size
1.7 模拟器
- 显示尺寸调节
Window -> Scale -> … [command + 1-5] - 设备操作
Hardware -> … - 返回出厂设置
Simulator -> Reset content and Settings…
1.8 真机调试
- 添加调试账号
Xcode -> Preferences -> Accounts -> + - 设置调试账号
Workspace -> General -> Identity -> Team 进行选择 -> Fix issues - 运行
首次运行会提示错误,需要真机验证
真机 -> 设置 -> 通用 -> 描述文件 -> 选中信任 -> 回到 Xcode 再次运行
1.9 App 基本概念
- iOS App 代码结构(这是 Objective-c 语言,Swift 有所不同,main 文件会被隐藏)
- main()
- UIApplicationMain()(生成一个 UIApplication 对象并设置成为该应用的代理。)
- UIApplication 对象
- UIApplicationDelegate
- iOS App 运行环境
- Sandbox
- 获取目录 NSHomeDirectory()
- iOS 应用都是一个 Bundle
- Bundle: 带有 Info.plist 字典的目录
- 通过 NSBundle 类访问其中的资源
- 主要是通过 mainBundle
- resource bundle 和 framework(可执行动态库)
- 查看 App Bundle
设置栏中选择设备 -> Generic iOS Device -> command + B 构建 -> Workspace -> Products -> xxx.app -> 右键 查看文件 -> 右键 显示包内容
<br />
3 Button - Storyboard 与代码之间联系方式
介绍最常用的 Interface 组件之一 UIButton,以及它的使用方法。
从而介绍 Outlet Action 等概念。
3.1 UIButton
3.2 IBOutlet
- IBOutlet Connection
把 Nib object 与 代码中的 IBOutlet 变量相连接-
在 Storyboard 中将组件与代码中的 IBOutlet 变量进行连接后,会在 Storyboard 代码中多出来这样一段连接说明
<connections> <outlet property="okLabel" destination="QJt-2z-ban" id="mhJ-Nu-TIR"/> </connections> // property 变量名称 // destination 界面上的组件名称 // id 标志这个连接本身
运行时调用
由于 xib 中存储的是界面模板,所以在允许的时候,类实例代码会触发界面的实例化方法。
最终调用[UINib instantiateWithOwner:options:]
方法实例化界面。
Owner 实际上是调用了一个按名字绑定的属性。[owner setValue:uiObj forKey:outlet.property]
-
其实我自己都看不懂这段在说什么……大概是说 outlet connection 其实是标注了界面与代码之间的关系,然后在程序运行的时候,会通过一系列 runtime 方法调用这种关系,并根据界面模板实例化界面组件,从而生成组件绘制吧。
- Action Connection
-
界面事件连接 IBAction
<connections> <action selector="buttonAction:" destination="BYZ-38-t0r" eventType="touchUpInside" id="BQA-pw-9f8"/> </connections> // selector 方法名称 // eventType 事件类型
-
<br />
4 Image
图片流:界面全部由现成的图片构成。耗内存,但是简便。
代码流:界面全部由代码绘制而成,省内存,适应性高。
4.1 UIImage
-
图片加载
-
图片动画
let anmiationImage = UIImage.animatedImageNamed("ImageArrayName", duration: 2.0) // ImageArrayName 是动画图片的前缀,动画图片资源应该按照该名称后面加数字来命名。 // duration 是总时长。 // KeyNote 可以导出动画的每帧图片。
4.2 Assert Catalog
-
Assert Catalog 介绍
模板会默认生成一个 Assert Catalog 文件并且其中有 Appicon 以用于给 App 提供系统图标。
直接用图片名字的办法加载图片,虽然简便,但是由于这样的做法会把图片缓存在内存中,在图片较多尺寸较大时会照成内存压力。 -
Assert Catalog 功能
添加图片:直接将图片资源拖入 Asset Catalog,或者下面的
+
号。资源属性:每个图片可以有三个尺寸以提供给不同的屏幕尺寸使用。还可以设置适用各种设备和各种特定尺寸 Attributes -> Devices。
-
图片切片:点击图片 -> Attributes -> Slicing -> Slices -> …
-
适用矢量图片
放置对应的图片格式进去 Assert Catalog 之后,然后设置其属性。
-
Attributes -> Devices -> Scale Factors -> Single Vector
<br />
5 第一个 App
5.1 需求分析
- 详细了解应用需求,需要确切了解用户想要的是什么。
- 详细规划应用的逻辑流程,各个模块功能的来由和去向。
5.2 程序设计
平衡设计原则:设计程序时为未来可能的需求做好准备。但是这种办法有好有坏,有时候考虑太多,就会导致当前事情难以完成。如果完全只考虑当前,就可能增加未来重构的次数。中间的度需要靠程序员把握。
- 走通流程图,确认游戏逻辑
- 确认静态数据结构
5.3 示例代码结构
各个代码模块之间的联系和关系的明确。
5.4 Keynote 课件展示
<br />
6 View Controller
6.1 简单的设计模式介绍
6.2 UIViewController
-
UIViewController 介绍
-
获取 ViewController
- 创建 rootViewController
- Info.plist 中的 UIMainStoryboardFile, NSMainNibFile 指定了根控制器的来源。
- UIApplication 会通过调用
_runWithMainScene:transitionContext:completion:
方法。 - 然后调用
_loadMainInterfaceFile
来取出 Info.plist 中 UIMainStoryboardFile 或者 NSMainNibFile 信息。 - 如果是前者,则再调用
_loadMainStoryboardFileNamed:bundle:
。 - 如果是后者,则再调用
_loadMainNibFileNamed:bundle:
。
- 加载好 rootViewController 之后就把这个视图控制器赋值给 appDelegate.window.rootViewController。
- 假如上述方法初始化界面失败,则会调用
UIApplicationDelegate didFinshLaunch
方法来给程序员一个使用程序初始化界面的时机。最开始时,也是只有这一个办法来初始化界面的。 - 如果以上两种办法都没有给
appDelegate.window.rootViewController
赋值,则这个应用的 window 就会为 nil 显示黑屏.
- 创建 rootViewController
-
获取 ViewController 的 View
- 自定义 ViewController 装载过程
- 调用
[UIViewController loadView]
如果有实现,调用之后就不会调用后面的方法了。如果是默认实现则会调用下面的其他方法。 - 调用
[UIViewController nibName]
如果是默认模板,则 nibName 应该是来自 Storyboard。如果是代码调用initWithNibName
则由程序员指定 nib. 如果两者都不是,则会调用下面的方法。 -
[UIViewController exisitingNibNameMatchingClassName:bundle:]
,它会根据 ViewController 方法猜测并且查找 Nib,如果都查找不到,系统会创建一个空白视图。
- 调用
- 要点
- isViewLoaded 判断 ViewController 的 View 是否已经加载好了。
- loadView 中不能调用 super.
- 自定义 ViewController 装载过程
6.3 View Controller Lifecycle
6.3 多个 View Controller
-
弹出新视图的方法
presentViewController:animation:completion:
- UIViewController 的 modalPresentationStyle 是设置弹出控制器风格的属性。
- UIViewController 的 modalTransitionStyle 是设置弹出动画风格的属性。
iOS 8+ 之后新方法
showViewController:sender
释放控制器
dismissViewControllerAnimated:completion:
-
回传数据:把父控制器作为子控制器的代理,通过回调函数来传递数据。并且由父控制器来控制子控制器的释放,而不是子控制器自己调用
dismissViewControllerAnimated:completion:
方法。
<br />
7 Storyboard
Storyboard 也是一个 xib 文件,只是它里面不只是放 View,而是放置 Scene.
可以点击 ViewController 然后直接拖出 Segue 到其他 ViewController 当中,从而创建没有组件触发事件的 Segue。
7.1 Storyboard Segue
-
使用代码进行 Segue 跳转
func segueAction() { // 0 以 Segue 跳转 performSegueWithIdentifier("SegueIdentifier", sender: nil) // 1 获取 ViewController if let nextViewController = storyboard?.instantiateViewControllerWithIdentifier("ViewControllerIdentifier") { showViewController(nextViewController, sender: nil) } }
-
Segue 传值
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // 每次有 Segue 被触发就会调用此函数,以提供传值时机。 }
-
Storyboard Segue 回退
@IBAction override func unwindForSegue(unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) { // @IBAction func unwindFuncName(segueName: UIStoryboardSegue) { } // 名称可以随意,参数至少要有一个 UIStoryboardSegue。用来作为 Storyboard 回退触发事件。 }
7.2 多 Storyboard
-
当场景太多的时候,可以把 Storyboard 分成多个文件。场景之间的过渡,可以通过两种办法实现。
- Storyboard Reference 组件,跟 ViewController 组件一样可以拖动到 Canvas 上。并且可以设置它指向的 Storyboard 文件,Reference ID(如果不指定就是 initial View Controller)。
- 选中需要放置在新 Storyboard 上的 ViewController,然后点击 Editor -> Refactor to Storyboard。然后就会创建新的 Storyboard 文件,并将选中的 ViewController 放置到其中。
-
获取其他 Storyboard
func muchStoryboard() { // 根据名称获取 Storyboard let storyboard = UIStoryboard(name: "StoryboardName", bundle: NSBundle.mainBundle()) }
<br />
8 App Lifecycle
8.1 应用启动
main - 启动程序
UIApplicationMain() - 启动应用代理
UIApplication - 启动消息循环
APPDelegate - 生成应用代理
-
根据 Storyboard 或者代码创建的 ViewController 加载 rootViewController
8.2 用户互动
RunLoop Mode: [source] 其实就是事件源。
main run loop 循环关注事件源。接收事件。
接收到事件就传递给 Application object。
Application object 对事件进行分发。
-
事件根据代码逻辑反馈到视图上。
8.3 AppDelegate
-
出生
-
application:willFinishLaunchingWithOptions:
事件
UI 已经加载出来了。RootViewController 已经创建好,只是还没访问它的 view 方法。
应用级的初始化工作最好都放在这个位置,但是不要在这里做太耗时的事件。
Options 会提供启动状态信息。
App Programming Guide for iOS 文档中的 Preserving Your App’s Visual Appearance Across Launches 中有详细的说明。-
application:didFinishLaunchingWithOptions:
事件
界面已经恢复过了,但是 UI 还没有放置到界面上。这时候代码已经开始执行,但是界面看不见,也不会进行响应。
依然是应用级别的初始化机会。
Options 会提供启动状态信息。
*applicationDidBecomeActive:
事件
应用已经要开始活动了的时机。 -
-
进入不活跃状态
-
applicationWillResignActive:
事件
-
-
进入后台状态
-
applicationDidEnterBackground:
事件
这是一个短暂的时机,默认是 5 秒内完成。但是可以通过beginBackgroundTask
方法可以获取大约 10 分钟的后台运行事件。
如果还需要更长的事件,需要编写后台运行程序。详细查阅文档。
-
-
应用关闭
-
applicationWillTerminate:
事件
如果你的应用刚好被挂起没有多久,然后就被关闭了,就会接收到这个事件。如果你已经被悬挂在后台了,那在关闭的时候就不会收到这个通知。
-
-
应用复活
-
applicationWillEnterForeground:
事件
应用即将回到前台的事件。
-
8.4 移动应用的特点。
移动应用的使用会非常的零散,会在各种状态中来回切换。
<br />
9 Navigation
9.1 Navigation Bar
9.2 UINavigationController
- Navigation Controller 的结构(属性)
- viewControllers (视图控制器数组,管理着导航控制器的所有视图控制器。)
- topViewController (最顶上的视图控制器,绝大多数时候跟 visibleViewController 是同一个,但也不绝对。)
- visibleViewController (当前显示的视图控制器。)
- navigationBar
- toolbar
- delegate
- viewControllers (视图控制器数组,管理着导航控制器的所有视图控制器。)
-
给现有的 ViewController 添加 NavigationController
- 选中 ViewController -> Editor -> Embed In -> Navigation Controller
- 拖动 NavigationController 到 Canvas -> 设置 ViewController 成为其 rootViewController
-
利用 UINavigationController 的 Delegate 方法时机来进行导航时的数据传递(但是尽可能还是用 Segue 方法来进行数据传递)
- navigationController:willShowViewController:animated: (一般数据传递会在这里进行。)
- navigationController:didShowViewController:animated:
9.3 在代码中使用 NavigationController
并不推荐使用代码创建,毕竟用 Storyboard 就很方便了。
setViewControllers:animated:
比较有时机意义,可以让导航不用每次都从 rootViewController 开始。更加灵活。
9.4 自定义导航栏
了解以下各个类的属性,并根据实际要求自定义。基本上都是 Storyboard 中的操作,太简单粗暴了无法语言描述。
苹果有提供 Customizing UINavigationBar 的代码示例,里面有各种各样的自定义方法。
- UINavigationBar
- UIBarItem
- UIBarButtonItem
- UIToolBar
导航栏标题之上的小字在 Navigation Item -> Prompt 中设置。
<br />
10 TabBarController
10.1 UITabBarController 的结构
Tab Bar Item 一般不超过五个,否则会被隐藏。
-
tabBar
- UITabBarItem
- .moreNavigationController
-
viewControllers
- customizableViewControllers
selectedViewController
-
delegate
- UITabBarControllerDelegate
10.2 UITabBarItem
属性对应样式。
10.3 在代码中使用 UITabBarController
记住在设置之时要设置好 ViewController 的 tabBarItem 属性。
10.4 自定义 TabBar
图标的使用请严格按照系统定义来用,否则会让用户混乱。
-
简易定制
-
中间按钮
放置 5 个页面。然后使用一个新的视图覆盖中间的那个按钮。
@implementation MyTabBar - (void) viewWillAppear:(BOOL)animated { [self addCenterButtonWithImage:[UIImage imageNamed:@"camera"] highlightImage:nil]; } // 计算按钮的位置并且放置到中间 -(void) addCenterButtonWithImage:(UIImage*)buttonImage highlightImage:(UIImage*)highlightImage { UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height); [button setBackgroundImage:buttonImage forState:UIControlStateNormal]; [button setBackgroundImage:highlightImage forState:UIControlStateHighlighted]; CGFloat heightDifference = buttonImage.size.height - self.tabBar.frame.size.height; CGPoint center = self.tabBar.center; center.y = center.y - heightDifference/2.0 - self.tabBar.frame.size.height/3.0; button.center = center; [button addTarget:self action:@selector(middleButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; } // It is OK to replace IBAction with void here. -(IBAction)middleButtonTapped:(id)sender { [self showViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"middlepopvc"] sender:self]; }
-
更大胆的变化
定制 UITableViewController,具体查看代码实现。( VerticalBar )
![](http://upload-images.jianshu.io/upload_images/721097-ff083038d253a2c2?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<br />
11 UITableView
UITableView 是日常开发使用最频繁的组件之一。由于我之前已经做过不少应用,所以听课的时候很多比较简单的东西就没有进行记录了。建议还是要多做几个 Demo 进行练习,并且多看文档。熟悉
UITableViewDataSource
以及UITableViewDelegate
的各种方法。
如果需要高度定制,还需要了解一下UIScrollViewDelegate
的方法,UITableViewDelegate
协议也继承自它,所以它的方法也一样有用,这样可以让你的 TableView 更加灵活个性。
-
认识 UITableView
-
一个 TableView 需要的功能。
-
iOS 中的 UITableView 结构
- UITableView
- UITableViewCell
- UIView
- UITableViewDataSource
- UITableViewDelegate
- NSIndexPath
- row
- section
-
UITableView 学习路线
11.1 UITableView 的基本使用
datas 是
[[String]]
格式的示例数据。
设置 UITableView 的风格:
.style
-
设置
.dataSource
实现UITableViewDataSource
中的常用方法。// MARK: - UITableViewDataSource // 设置表格 Section 数量 func numberOfSectionsInTableView(tableView: UITableView) -> Int { return datas.count } // 设置各个 Section 的 Row 数量 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return datas[section].count } // 设置每个 Cell 的具体内容 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("CellIndetifier")! cell.textLabel?.text = datas[indexPath.section][indexPath.row] return cell } // 设置表格表头文字 func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return "Header" } // 设置表格表尾文字 func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { return "Footer" }
-
设置
.delegate
实现UITableViewDelegate
中的常用方法。// MARK: - UITableViewDelegate // 设置表格各个 Section 的表头视图。 func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { return nil } // 设置表格各个 Section 的表尾视图。 func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { return nil } // 选中某 Row 时触发的事件。 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { // ... }
11.2 UITableViewCell
注意:prepareForSegue 事件触发时,目标 ViewController 还没调用 ViewDidLoad
- Cell 数据传递
在didSelectRowAtIndexPath
方法中调用performSegueWithIdentifier
的话,可以直接把indexPath
作为 sender 参数传递到prepareForSegue
中。这样就可以把对应数据传递给下一个 ViewController 了。 - Cell 高度
- 所有行都一样高则设置
tableView.rowHeight
会通过UITableViewAutomaticDimension
自动再推算调整一下。 - 高度都不同则通过
UITableViewDelegate
的tableView:heightForRowAtIndexPath:
方法进行设置。 - 也可以通过设置
tableView.estimatedRowHeight
来设置一个预估高度。
- 所有行都一样高则设置
- 定制 Cell - Prototype Cell
可以在 Storyboard 中的 cell 进行自定义设计。
-
通过 xib 创建 Cell
let nib = UINib(nibName: "CellXibName", bundle: nil) // nil is UIBundle.mainBundle() tableView.registerNib(nib, forCellReuseIdentifier: "CellIdentifier")
-
通过全代码设置 Cell,但是必须要在自定义 Cell 类中重载
initWithStyle
方法。tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "CellIdentifier")
11.3 UITableViewController
RefreshControl 的使用。
-
下拉刷新支持
-
数据刷新
11.4 UITableView 交互
-
选中
-
控制表格滚动
-
表格编辑支持
-
编辑模式处理过程
-
带索引的表格
-
索引本地化
-
高亮与菜单
-
表格与搜索
<br />
<br />
<br />