segue
1 - 在 Warrior 场景中拖入一个 BarButtonItem ,并将它的 System Item 改为 Add
2 - 在编辑器中新拖一个 TableViewController,放置在 Warrior 场景右边,然后按住 ctrl,自 Add 按钮始拖至新场景中,放开鼠标之后,就会出现以下选项
3 - 选中 Modal(模态),就会出现一种新的箭头形式:这个场景就会自动和这个按钮建立联系,从而自动归入到 NavigationController 栈中,这种链接形式被官方称为 segue(pronounce: seg-way)
注: - segue 表面翻译是联线的意思,其实它的意思是转换,这表示它从一种场景转换到另外一种场景中。之前我们使用的连接都是描述一种场景包含另一种场景的,而对于联线来说,它会改变屏幕中显示的内容,而且必须由交互动作触发:如轻拍或其它手势
- 联线真正了不起的地方在于:你不再需要写任何代码来转入一个新的场景,也不用再将你的按钮和 IBAction 连接到一起,我们刚才做的,直接将按钮和场景链接起来,就能够完成这项工作
4 - 运行代码,按 + 按钮,就会推出了一个新的列表:这种叫做模态转换,新的场景完全盖住了旧的那个,致使用户无法再与上一个场景交互,除非先关闭这个场景
5 - 联线只能够把你送到新的场景,你要是想回来,就得使用 Delegate Pattern(代理模式)。首先,必须给这个新的场景设置一个独有的类,继承自 UITableViewController,命名 WarriorDetailsViewController
6 - 为了把它和 storyboard 相联,在 storyboard,选择新建的 Table View Controller 场景,将它的子类设置为 WarriorDetailsViewController,千万不要忘记这一步
7 - 现在,我们把新场景的标题改为 AddWarrior,分别加入 Save 和 Cancel 两个导航栏按钮,完成之后应该是这个样子。注: - 由于场景 AddWarrior 的呈现方式我们选择的是模态,添加 BarButtonItem 前要先拖进个 NavigationBar
8 - 在 WarriorDetailsViewController.h 中,添加代码:这里会声明一个代理机制,完成当用户点击 Cancel 或 Save 按钮时,将用它来交互 AddPlayer 场景和主场景之间通讯的功能
1 #import <UIKit/UIKit.h> 2 3 @class WarriorDetailsViewController; 4 @protocol WarriorDetailsViewControllerDegegate <NSObject> 5 6 - (void)warriorDetailsViewControllerDidCancel:(WarriorDetailsViewController *)controller; 7 - (void)warriorDetailsViewControllerDidSave:(WarriorDetailsViewController *)controller; 8 @end 9 10 @interface WarriorDetailsViewController : UITableViewController 11 12 @property (nonatomic,weak) id <WarriorDetailsViewControllerDegegate> delegate;// 代理 13 14 - (IBAction)cancel:(id)sender;// 取消 15 - (IBAction)save:(id)sender;// 存储 16 17 @end
9 - 回到 srotyboard 中,将 Cancel 和 Save 分别与动作方法建立链接
10 - 在 WarriorDetailsViewController.m 中,添加代码
1 - (IBAction)cancel:(id)sender { 2 [self.delegate warriorDetailsViewControllerDidCancel:self];// 一般来说一定要为代理制定一个对象参数,这样它才知道向那里发送信息 3 } 4 5 - (IBAction)save:(id)sender { 6 7 [self.delegate warriorDetailsViewControllerDidSave:self]; 8 }
11 - 现在我们已经为 WarriorDetailsViewController 设置了一个代理协议,接下来就是要找个委托来实现这个协议,很明显,WarriorsViewController 就是这个管事婆
1 #import <UIKit/UIKit.h> 2 #import "WarriorDetailsViewController.h" 3 @interface WarriorsViewController : UITableViewController<WarriorDetailsViewControllerDegegate> 4 5 @property(nonatomic,strong)NSMutableArray *warriorsArray; 6 7 @end
12 - PlayersViewController.m 中
1 #import "WarriorDetailsViewController.h"
1 //当使用 segue 的时候,就必须加入此方法 2 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ 3 4 if([segue.identifier isEqualToString:@"AddWarrior"]){ 5 6 WarriorDetailsViewController *wdVC = (WarriorDetailsViewController*)segue.destinationViewController; 7 wdVC.delegate = self;// 指定代理 8 } 9 }
1 //实现代理 2 - (void)warriorDetailsViewControllerDidCancel:(WarriorDetailsViewController *)controller{ 3 4 [controller dismissViewControllerAnimated:YES completion:nil]; 5 } 6 7 - (void)warriorDetailsViewControllerDidSave:(WarriorDetailsViewController *)controller{ 8 [controller dismissViewControllerAnimated:YES completion:nil]; 9 }
13 - 试着运行一下这个应用,在 Warrior 场景中点击 + 按钮,然后试着关闭 AddWarrior 场景,然并卵:因为我们还没有给 segue 指定一个 Identifier,而 parepareForSegu 需要检查 AddWarrior 的身份,这是必须的(因为你有可能会同时使用多个联线)
14 - 在 storyboard 中,点击 AddWarrior 场景和 Warrior 场景之间的联线,在属性监控制器中,将 Identifier 设置为 AddWarrior
小结
1 - 为了完成一个联线,你需要做的几件事情
(1)首先,从起始的控件做一条联线到目标场景
(2)将这个联线制定一个 Identifier
(3)为目标场景制作一个代理方法:a. 在原始场景执行 prepareForSegue 方法; b. 在所有其它需要和原始场景交流的地方实现代理
2 - 返回功能必须要使用代理,因为根本没有反向联线这种东西,当 sugue 被启动之后,它将会创造出一个目标场景的新实例。你当然可以做一个从目标场景回到原始场景的联线,但是结果可能与你希望的大相径庭。 因为它并不会关闭当前场景并返回原始场景,而是会创建一个原始场景的新实例,这种情况会不停循环,知道把内存耗尽为止
注: - 请记住:segue 只用于打开新的场景