Your SlideShare is downloading. ×
07 View Controllers
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

07 View Controllers

342
views

Published on

iOS 视图控制器

iOS 视图控制器

Published in: Technology

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
342
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 视图控制器(View Controllers)范圣刚,princetoad@gmail.com, www.tfan.org
  • 2. Quiz 和 QuizViewController 回顾• 在第⼀一个 session 的 Quiz 应⽤用程序中,我们把所 有的代码都写在 QuizViewController 类中。这个类 的⼀一个实例是 Quiz 应⽤用的控制器• 它有指向屏幕上的 labels 的指针,指向按钮的指 针,这些按钮被按下时会给它发送消息。还有指 向组成应⽤用数据的模型对象的指针• 对于界⾯面只有⼀一屏的 Quiz 应⽤用,只有⼀一个 controller 对象就⾜足够了• ⼤大多数应⽤用具有不⽌止⼀一个屏幕的界⾯面,⽽而且有⾮非 常多的对象需要进⾏行管理,设计 iOS 应⽤用时最好 针对每⼀一屏都有⼀一个 controller
  • 3. UIViewController
  • 4. • ⼀一个 UIViewController 实例专注在控制应⽤用程序内的 ⼀一个单独的屏幕• 每个 UIViewController 具有⼀一个指向 UIView 或者 UIView ⼦子类的实例的 view 属性,这个 view 就是它 的 screen• 通常情况下,这个 view 是⼀一个全屏视图。⽽而且更多 的时候,这个 view 也具有 subviews。这样⼀一个 view controller 控制的就是⼀一个 view hierarchy• 因为这个 view 属性是整个 hierarchy 的 root,当 view controller 的 view 被作为⼀一个subview 添加到 window 时,整个 view hierarchy 就被添加了
  • 5. 创建 HypoTime从 Empty Application 模版创建⼀一个新的 iOS 项⺫⽬目,命名为 HypnoTime。按右边的图进⾏行配置:
  • 6. 两个 UIViewController 的⼦子类• 这个应⽤用我们将创建两个 UIViewController 的⼦子类 • HypnosisViewController • TimeViewController• 每个 view controller 将会控制⼀一个 view,⽤用户将 能够在这些 views 之间切换,取决于他们是否想 被催眠或者只是想知道现在是⼏几点• view 之间的切换将会由另外⼀一个类 UITabBarController 来处理
  • 7. ⼦子类化 UIViewController• 我们不会直接创建 UIViewController 的实 例,⽽而是创建 UIViewController 的⼦子 类来实例化• ⽣生成 HypnosisViewControlle r(File -> New File -> iOS -> Cocoa Touch -> Objective-C class)
  • 8. HypnosisViewController• view controller 负责创建它的 view hierarchy• HypnosisViewController 的 view hierarchy 将仅由 ⼀一个 view 组成。就是我们前⾯面创建的 UIView 的 ⼦子类 HypnosisView• 在 Finder ⾥里定位到 HypnosisView.h 和 HypnosisView.m ⽂文件,把他们拖到 HypnoTime 项 ⺫⽬目导航器中• 在出现的窗⼝口中,勾选“Copy items into destination group’s folder”• 同时勾选把它们添加到 target - “HypnoTime”
  • 9. 添加 HypnosisView 到 HypnoTime
  • 10. loadView • UIViewController ⼦子类通过重写 loadView ⽅方法来创 建它的 view hierarchy • 这个⽅方法创建⼀一个 view 的实例,并且把它设成 view controller 的 view • 在 HypnosisViewController.m 中重写 loadView,确 保在⽂文件顶部导⼊入了 HypnosisView 的头⽂文件// 重写 loadView- (void)loadView{ // 创建⼀一个 view CGRect frame = [[UIScreen mainScreen] bounds]; HypnosisView *view = [[HypnosisView alloc] initWithFrame:frame]; // 把它设成 view controller 的 view [self setView:view];}
  • 11. 重写 loadView (代码) #import "HypnoViewController.h" // 导⼊入 HypnosisView 头⽂文件 #import "HypnosisView.h" @interface HypnoViewController () @end @implementation HypnoViewController // 重写 loadView - (void)loadView { // 创建⼀一个 view CGRect frame = [[UIScreen mainScreen] bounds]; HypnosisView *view = [[HypnosisView alloc] initWithFrame:frame]; // 把它设成 view controller 的 view [self setView:view]; }
  • 12. rootViewController• 在 HypnoAppDelegate.m 中,创建⼀一个 HypnosisViewController 的实例并且把它设成 UIWindow 的 rootViewController• 确保在⽂文件顶部导⼊入了 HypnosisViewController.h 头⽂文件
  • 13. 设置 rootViewController(代码)#import "HypnoAppDelegate.h"// 导⼊入 HypnosisViewController 的头⽂文件#import "HypnoViewController.h"@implementation HypnoAppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. // 实例化⼀一个 HypnosisViewController 的实例,并设置成 window 的 rootViewController HypnoViewController *hvc = [[HypnoViewController alloc] init]; [[self window] setRootViewController:hvc]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 14. HypnosisViewController 的 HypnosisView
  • 15. 应⽤用的对象⽰示意图• 把⼀一个 view controller 设成 window 的 rootViewController 就把 这个 view controller 的 view 添加成了 window 的 subview• 同时把 view 的⼤大⼩小⾃自 动调整成和 window 同 样⼤大⼩小
  • 16. setRootViewController • 如果我们⾃自⼰己写 UIWindow 的 setRootViewController, ⼤大概是下⾯面这样:// UIWindow setRootViewController- (void)setRootViewController:(UIViewController *)vc{ UIView *rootView = [vc view]; CGRect viewFrame = [self bounds]; [rootView setFrame:viewFrame]; [self addSubview:rootView];}
  • 17. 第⼆二个 UIViewController• HypnoTime 的第⼆二个 UIViewController 的⼦子类 • TimeViewController• TimeViewController 的 screen 将会显⽰示⼀一个 UILabel,和⼀一个把 label 更新到当前时间的 UIButton• 这个 UIView 将会具有两个 subview:按钮和标签#import <UIKit/UIKit.h>@interface TimeViewController : UIViewController@end
  • 18. TimeViewController 的 view hierarchy
  • 19. 编程或者从 XIB 创建 view• 创建 HypnosisViewController 的 view hierarchy 时, 我们通过编程来实现的:在 loadView 中,实例化了 ⼀一个 HypnosisView, 然后把它设置成 view (view controller 的 view 属性)。这个 view 没有任何的 subview• TimeViewController 的 view 将会有两个 subview。当 ⼀一个 view controller 的 view 具有 subview 的时候, 最好在 XIB ⽂文件中创建和加载它的 view hierarchy, ⽽而不是重写 loadView• 程序运⾏行起来以后,通过编程或者从 XIB ⽂文件创建的 view 没有什么区别,只是 XIB ⽂文件更易于放置多个 view objects
  • 20. TimeViewController.xib• File -> New -> File, iOS, User Interface, Empty 模版• 弹出窗⼝口的 Device Family 选“iPhone”• 命名为 TimeViewController• 命名假设的重要性• 在 project navigator 中选中这个⽂文件以使其在 editor area 显⽰示
  • 21. File’s Owner• XIB ⽂文件是如何⼯工作的的?• XIB ⽂文件包含的是对象:把对象拖到画布上就把对 象保存到 XIB ⽂文件了。当 XIB ⽂文件被加载的时候, 这些对象被加载回进内存中
  • 22. TimeViewController 的 XIB ⽂文件•在 TimeViewController.xib 中,拖拽⼀一个 UIView 到画布上,然后拖拽 ⼀一个 UIButton 和⼀一个 UILabel 到 view 上• 给按钮⼀一个标题: What time is it?• 给标签⽂文本: ???, 然后 让它居中
  • 23. TimeViewController.xib 中的 Objects• 我们可以看到这些对 象都显⽰示在 Objects 段 下⾯面• 显⽰示在 Objects 段下⾯面 的对象都是被保存到 XIB ⽂文件中的对象• 这种类型的存储有⼀一 个专有名词叫做: archiving,这些对象 也就被称作 archived objects
  • 24. placeholder 对象• XIB ⽂文件中还有另外⼀一 种类型的对象: placeholder objects• Placeholder 区段下⾯面 有两个对象: • File’s Owner(重要!) • First Responder
  • 25. File’s Owner• 为什么需要 File’s Owner?• 当 view controller 加载它的 view 的时候,它会设置 view 属性,这样它就知道它的 view 是什么然后可以把 它放到屏幕上• 对于 HypnosisViewController,我们通过编程来做这 些,这些操作在 loadView 中实现并且所有的设置都是 在编译期间完成的• TimeViewController 并⾮非如此,当⼀一个 TimeViewController 的实例需要加载 view 时,它将会加 载 XIB ⽂文件,这时 XIB ⽂文件中的所有的 archived objects 都会被创建,然⽽而 TimeViewController 并不知道这些对 象中的哪⼀一个是它的 view
  • 26. 作为 hole 的 File’s Owner• File’s Owner 是 XIB ⽂文件的⼀一个 hole• 在配置界⾯面的时候,我们在 XIB ⽂文件中的对象和 File’s Owner 之间建⽴立连接• 当 XIB ⽂文件被加载时,TimeViewController 把它⾃自 ⼰己置⼊入 File’s Owner 的 hole,然后所有的在 File’s Owner 和 archived objects 之间的连接都成了到 TimeViewController 的• 为了能够设置 TimeViewController 需要的连接,我 们必须告诉 Xcode TimeViewController 是要把⾃自⼰己 放到这个 hole ⾥里的对象的类
  • 27. Identity inspector for File’s Owner• 在 outline view 选中 File’s Owner 对象,然 后点击 inspector 区域 的“Identity inspector”,把 Custom Class 下⾯面的 class 改成 “TimeViewController”
  • 28. view outlet• Control-click File’s Owner 弹出可⽤用连接的⾯面板,我 们指定的类是⼀一个 UIViewController 的⼦子 类,我们就被提供了⼀一个 view outlet• 把 view outlet 连到 XIB ⽂文 件的 UIView 对象• 现在当 TimeViewController 加载 XIB ⽂文件时,就具有了适 当的连接,并且可以加载 它的 view 了
  • 29. File’s Owner
  • 30. outlet• 这样在 XIB ⽂文件中的⼀一个 outlet 连接就等同于给 outlet 对应的对象发送⼀一个基于 outlet 名称的 setter 消息• 例如,当 XIB ⽂文件被加载时,把⼀一个对象设置成 view outlet,将会发送⼀一个 setView: 消息给那个 对象,这个⽅方法的参数是连接那头的对象
  • 31. TimeViewController 作为 rootViewController• 打开 HypnoAppDelegate.m, 创建⼀一个 TimeViewController 的实例,把它设成 window 的 rootViewController。确保导⼊入 TimeViewController.h 头⽂文件• 构建并运⾏行,我们可以看到在 TimeViewController.xib 中创建的 TimeViewController 的 view
  • 32. TimeViewController 作为 rootViewController#import "HypnoAppDelegate.h"// 导⼊入 TimeViewController 头⽂文件#import "TimeViewController.h"@implementation HypnoAppDelegate- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; TimeViewController *tvc = [[TimeViewControlleralloc] init]; [[self window] setRootViewController:tvc]; self.window.backgroundColor = [UIColorwhiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 33. outlet 和 method • TimeViewController 在控制这个 view hierarchy, TimeViewController 负责在按钮被按下时更新 label,所以TimeViewController 要作为 UIButton 的 target,并且要具有⼀一个指向 UILabel 的指针 • 在 TimeViewController.h 中声明⼀一个 outlet 和⼀一个 ⽅方法#import <UIKit/UIKit.h>@interface TimeViewController : UIViewController{ IBOutlet UILabel *timeLabel;}- (IBAction)showCurrentTime:(id)sender;@end
  • 34. 建⽴立连接• 打开 TimeViewController.xib,把 File’s Owner 的 timeLabel outlet 连接到 UILabel• 然后连接 UIButton 到 File’s Owner,并且选择 showCurrentTime:• 这些连接如下⼀一⻚页的图所⽰示:
  • 35. TimeViewController
  • 36. 在 TimeViewController.m 中实现 action ⽅方法- (IBAction)showCurrentTime:(id)sender{ NSDate *now = [NSDate date]; NSDateFormatter *formatter = [[NSDateFormatteralloc] init]; [formattersetTimeStyle:NSDateFormatterMediumStyle]; [timeLabel setText:[formatterstringFromDate:now]];}
  • 37. 现在应⽤用的对象⽰示意图
  • 38. 回顾:view controller 和 加载 view• view controller 控制⼀一个 screen,这个 screen 就是⼀一个 view• 这个 view controller 的 view,⼜又将具有 subviews,构 成了⼀一个 view hierarchy• ⼀一个 view controller 可以通过两种途径得到它的 view: • 其 view 没有任何 subviews 的 view controller 可以通过重写 loadView: 来创建⼀一个 view 实例,然后给⾃自⼰己发送 setView: • 具有⾮非常复杂 view hierarchy 的 view controller 可以通过把 它的 view outlet 连接到 XIB 中 archived 的顶层 view 的⽅方式 从⼀一个 XIB ⽂文件中加载它的 view
  • 39. UITabBarController
  • 40. • view controller 可以根据⽤用户的动作呈现另⼀一个 view controller 出来• UITabBarController 就是这类 view controllers 之 ⼀一,我们将使⽤用⼀一个 UITabBarController 在 HypnosisViewController 和 TimeViewController 的 实例之间切换• UITabBarController 持有⼀一个 UIViewController 的数 组,它也在屏幕底部维护了⼀一个标签栏(tab bar), 其数组中的每⼀一个 view controller 都有⼀一个标签• 点击标签的结果就是和这个标签关联的 view controller 的 view 被呈现出来
  • 41. 创建⼀一个 UITabBarController• 在 HypnoAppDelegate.m 中,创建⼀一个 UITabBarController 的实例,把两个 view controller 都给它,然后把它设置成 window 的 rootViewController
  • 42. 创建 UITabBarController(代码)- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]bounds]]; // Override point for customization after application launch. HypnoViewController *hvc = [[HypnoViewController alloc] init]; TimeViewController *tvc = [[TimeViewController alloc] init]; UITabBarController *tabBarController = [[UITabBarController alloc]init]; NSArray *viewControllers = [NSArray arrayWithObjects:hvc, tvc, nil]; [tabBarController setViewControllers:viewControllers]; [[self window] setRootViewController:tabBarController]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 43. 点击底部的⿊黑⾊色标签可以切换 view controller
  • 44. UITabBarController 的 view• UITabBarController 是 window 的 rootViewController。这意味着 UITabBarController 本⾝身是 UIViewController的⼀一个⼦子类• 那么它就具有 view 属性,它的 view 是⼀一个具有 两个 subviews 的空⽩白 UIView • tab bar 标签栏 • 选中的 view controller 的 view
  • 45. UITabBarController ⽰示意图
  • 46. tabBarItem 属性和 UITabBarItem
  • 47. • 标签栏上的每个标签可以显⽰示⼀一个 title 和⼀一个 image• 为了这个⺫⽬目的,每个 view controller 维护⼀一个 tabBarItem 属性• 当⼀一个 view controller 被⼀一个 UITabBarController 包含时,它的标签栏条⺫⽬目出现在标签栏上
  • 48. UITabBarItem ⽰示例
  • 49. 为两个 view controller 设置标题• 打开 HypnosisViewController.m, 重写 UIViewController 的 designated initializer, initWithNibName:bundle:, 为 HypnosisViewController 获得然后设置⼀一个 tab bar item• 然后打开 TimeViewController.m, 进⾏行同样的操作
  • 50. 设置 UITabBarItem 的代码- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization // 获取 tab bar item UITabBarItem *tbi = [self tabBarItem]; // 给它⼀一个标题 [tbi setTitle:@"Hypnosis"]; } return self;}- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization UITabBarItem *tbi = [self tabBarItem]; [tbi setTitle:@"Time"]; } return self;}
  • 51. 设置了标题的 tabBarItem
  • 52. 为每⼀一个标签增加图⽚片• 把图⽚片⽂文件Hypno.png, Time.png, Hypno@2x.png, Time@2x.png 拖到项⺫⽬目中,勾选拷⻉贝到项⺫⽬目⺫⽬目录 选项• 然后再编辑 initWithNibName:bundle: 的代码
  • 53. 设置标签栏图⽚片的代码- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { UITabBarItem *tbi = [self tabBarItem]; [tbi setTitle:@"Hypnosis"]; UIImage *image = [UIImage imageNamed:@"Hypno.png"]; [tbi setImage:image]; } return self;}- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization UITabBarItem *tbi = [self tabBarItem]; [tbi setTitle:@"Time"]; UIImage *image = [UIImage imageNamed:@"Time.png"]; [tbi setImage:image]; } return self;}
  • 54. 设置了 image 的标签栏
  • 55. view controller 的⽣生命周期
  • 56. • ⼀一个 view controller 当被 allocated, 然后发送⼀一 个 initializer 消息后就开始了它的⽣生命周期• ⼀一个 view controller 将会看到它的 view 被创建, 移动到屏幕上,移离屏幕,销毁,以及再次创建 - 这个过程也许会有很多次以上• 这些事件构成了 view controller 的⽣生命周期
  • 57. 初始化 view controller• UIViewController 的 designated initializer 是 initWithNibName:bundle: 。这个⽅方法使⽤用两个参 数指定了在 bundle ⾥里⾯面的 view controller 的 XIB ⽂文件的名称• 两个参数都传⼊入 nil 表⽰示:当加载你的 view 的时 候,在 application bundle 中搜索名称和你的类名 相同的 XIB ⽂文件• 例如: TimeViewController 将会加载 TimeViewController.xib ⽂文件• 可以把下⾯面的代码添加到 TimeViewController.m 会 理解的更清楚⼀一点:
  • 58. nibNameOrNil- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; // 获得到 application bundle 对象的指针 NSBundle *appBundle = [NSBundle mainBundle]; self = [super initWithNibName:@"TimeViewController" bundle:appBundle]; if (self) { // Custom initialization UITabBarItem *tbi = [self tabBarItem]; [tbi setTitle:@"Time"]; UIImage *image = [UIImage imageNamed:@"Time.png"]; [tbi setImage:image]; } return self;}
  • 59. init • 实际开发过程中,我们⼀一般都使⽤用 UIViewController ⼦子类的名称作为 XIB ⽂文件的名称 • 因此,当创建⼀一个 view controller 时,我们只需要 发送 init ,等同于给 initWithNibName:bundle: 的 两个参数都传⼊入了 nil • 需要的话可以通过重写 initWithNibName:bundle: 来执⾏行⼀一些额外的初始化⼯工作TimeViewController *tvc = [[TimeViewController alloc] init];// 等同于TimeViewController *tvc = [[TimeViewController alloc] initWithNibName:nil bundle:nil];
  • 60. UIViewController 和延迟加载• 当⼀一个 view controller 被实例化的时候,它不会⽴立 即创建和加载它的 view• 只有当 view 将要在屏幕上显⽰示的时候,⼀一个 view controller 才会特意创建它的 view• 通过在只有需要的时候才加载视图,应⽤用程序不 会在它不需要的时候占⽤用内存
  • 61. viewDidLoad• 所有的 UIViewController 都实现了⼀一个 viewDidLoad ⽅方法,当它加载了它的 view 以后就 会⽴立即执⾏行• 我们在我们的两个 view controller ⾥里⾯面重写这个⽅方 法在控制台记录⼀一些消息• 构建并运⾏行,可以看到控制台报告 HypnosisViewController ⽴立即加载了它的 view;点 击 TimeViewController 的标签以后,控制台才报告 view 现在被加载 - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"TimeViewController 加载了它的 view"); }
  • 62. Appear 和 Disappear • 除了加载和卸载以外,view controller 也会在特定 的时间出现或者消失 • view controller 只会被创建⼀一次,但是它的 view 通常会显⽰示(释放或者隐藏)多次 • 我们可以在这些⽣生命周期事件发⽣生时做⼀一些⾃自定 义的操作,⽐比如我们可以让 TimeViewController 的 view 每次显⽰示时,可以显⽰示最新时间- (void)viewWillAppear:(BOOL)animated; // Called when the view is aboutto made visible. Default does nothing- (void)viewDidAppear:(BOOL)animated; // Called when the view has beenfully transitioned onto the screen. Default does nothing- (void)viewWillDisappear:(BOOL)animated; // Called when the view isdismissed, covered or otherwise hidden. Default does nothing- (void)viewDidDisappear:(BOOL)animated; // Called after the view wasdismissed, covered or otherwise hidden. Default does nothing
  • 63. 重写 viewWillAppear - (void)viewWillAppear:(BOOL)animated { NSLog(@"CurrentTimeViewController will appear"); [super viewWillAppear:animated]; [self showCurrentTime:nil]; } - (void)viewWillDisappear:(BOOL)animated { NSLog(@"CurrentTimeViewController will disappear"); [super viewWillDisappear:animated]; }
  • 64. view controller 中 view 的⽣生命周期
  • 65. 视图控制器的⼦子类和模版• 实际开发过程中,我们可以在使⽤用 UIViewController 模版的同时勾选上⽣生成相应的 XIB ⽂文件• 这样 XIB ⽂文件的 File’s Owner 已经被设置成 UIViewController 的类,同时 UIView 的实例已经被 挂接到 File’s Owner 的 view outlet
  • 66. 练习1:再加⼀一个 Tab• 创建⼀一个新的 UIViewController ⼦子类,它的 view 应该是 MKMapView 的⼀一个实例• 使这个 view controller 成为 UITabBarController 的 第三个 view controller
  • 67. 练习2:Controller Logic• 增加⼀一个 UISegmentedControl 到 HyposisViewController 的 view,带着三个 segments:Red, Green 和 Blue• 当⽤用户 tap segmented control 时,改变 HyposisView 中 circles 的颜⾊色
  • 68. 补充阅读:main 函数和 UIApplication • C 应⽤用程序都是从执⾏行⼀一个 main 函数开始, Objective-C 应⽤用程序也是⼀一样的int main(int argc, char *argv[]){ @autoreleasepool { return UIApplicationMain(argc, argv, nil,NSStringFromClass([HypnoAppDelegate class])); }}• UIApplicationMain 函数⽣生成了⼀一个 UIApplication 类 的实例;对于每⼀一个应⽤用来说,都有⼀一个单独的 UIApplication 实例,⽤用于维护 run loop• UIApplicationMain 还⽣生成⼀一个 作为 UIApplication 的 delegate 类的实例。最后⼀一个参数就是 delegate 类的名称
  • 69. application:didFinishLaunchingWithOptions: • 在 run loop 将要开始接收事件前,application 会 发送给它的 delegate ⼀一个消息,告诉它“ 准备好 了,我们要开始啦!”,这个消息就是 application:didFinishLaunchingWithOptions: • 我们在 HypnosisAppDelegate.m 中实现这个⽅方法 来创建在应⽤用程序中使⽤用的 window 和 controller 对象 • 所有的 iOS 应⽤用程序都遵循这种模式
  • 70. 补充阅读2:视⺴⽹网膜屏(Retina) 显⽰示• Retina 和早期设备的 320x480 像素⽐比较⽽而⾔言具有更⾼高的 分辨率(640x960)• 如何才能让图形在两种显⽰示上都能得到最佳显⽰示?• 对于⽮矢量图形,像 HypnosisView 的 drawRect: ⽅方法和绘 制⽂文本,同样的代码会渲染的和设备允许的⼀一样清晰• 如果使⽤用 Core Graphics 函数绘制,这些图形在不同的 设备上会有不同的表现• 在 Core Graphics 中,也被称作 Quarz,我们使⽤用名词 points 描述 lines(直线),curves(曲线),text(⽂文 本) 等。在⾮非 Retina 显⽰示上,⼀一个 point 是1x1像素; 在 Retina 显⽰示上,⼀一个 point 是 2x2 像素
  • 71. 不同分辨率的渲染
  • 72. 图像拉伸• 位图(像 JPEG 或 PNG ⽂文件),如果图像没有适合设备的屏幕类型,将会变得没有吸引⼒力• 假如你的应⽤用包含了⼀一个 25x25 像素的⼩小图像,如果它在 Retina 显⽰示器上显⽰示时,图像必须被拉伸来覆盖 50x50 的区域。• 从这⼀一点上来讲,系统使⽤用了⼀一种叫做抗锯齿的平均化的⽅方式来使图像看起来没有锯齿。结果是图像没有锯齿 - 但是模糊
  • 73. 拉伸图像后引起的模糊
  • 74. @2x• 可以使⽤用⼤大⽂文件替代,但是图像缩⼩小时⼜又会在另⼀一 个⽅方向引起问题• 唯⼀一的⽅方案是在应⽤用程序绑定两个⽂文件:⼀一种是在 ⾮非 Retina 屏幕上采⽤用分辨率等于 points 数量,另 外⼀一种是在 Retina 显⽰示上采⽤用 points 两倍的分辨 率• 幸运的是我们不需要写额外的代码来处理在哪种设 备上加载哪种图⽚片,我们需要做的就是在⾼高分辨率 图⽚片后⾯面加上 @2x 后缀。然后当使⽤用 UIImage 的 imageNamed: ⽅方法来加载图⽚片时,这个⽅方法会在 bundle 中查找,然后拿到适合特定设备的⽂文件