Xcode - storyboard_OC版 05:segue

segue

1 - segue 表面翻译是联线的意思,其实它的意思是转换,表示它从一种场景转换到另外一种场景中。之前我们使用的链接都是描述一种场景包含另一种场景的,而对于联线来说它会改变屏幕中显示的内容,而且必须由交互动作触发:如轻拍或其他手势 。联线真正了不起的地方在于你不再需要写任何代码来转入一个新的场景,也不用再将你的按钮和 IBAction 连接到一起。直接将按钮和场景链接起来就能够完成这项工作 

2 - 如何使用 segue

① 在 Warrior Scene 中拖入一个 BarButtonItem ,并将它的 System Item 换成 Add

② 在故事面板中新拖一个 TableViewController 控件,然后按住 ctrl 自 Add 按钮始拖至目标场景中就会出现一个选相框

选中 Modal 就会出现一种新的箭头形式,这个场景就会自动和这个按钮建立联系,从而自动归入到 NavigationController 栈中,这种链接形式被官方称为 segue

3 - 现在运行程序,点击 Add 时会推出新场景,但是你会发现:来的时候好好的,回不去了!

  

注:联线只能够把你送到新的场景,你要是想回来就得使用 Delegate Pattern(代理模式)

4 - 首先新建 UITableViewController 子类 WarriorDetailsViewController,在 storyboard 里将它置为新场景 Table View Controller Scene 的 Custom Class。把新场景标题改为 AddWarrior,分别添加 Save 和 Cancel 两个按钮并完成关联,最终应该是这个样子。注:由于场景 AddWarrior 的呈现方式我们选择的是模态,添加 BarButtonItem 前要先拖进个 NavigationBar

5 - 在 WarriorDetailsViewController.h 中声明代理,完成当用户点击 Cancel 或 Save 按钮时将用它来交互 AddWarrior Scene 和主场景之间通讯的功能

 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

6 - 配置 WarriorDetailsViewController.m 中的 cancel/Save 方法

 1 - (IBAction)cancel:(id)sender {
 2     
 3     // 一般来说一定要为代理制定一个对象参数,这样它才知道向那里发送信息
 4     [self.delegate warriorDetailsViewControllerDidCancel:self];
 5 }
 6 
 7 - (IBAction)save:(id)sender {
 8 
 9     [self.delegate warriorDetailsViewControllerDidSave:self];
10 }

7 - 在 WarriorsViewController 实现代理

  1 #import "WarriorsViewController.h"
  2 #import "Warrior.h"
  3 #import "WarriorCell.h"
  4 #import "WarriorDetailsViewController.h"
  5 @interface WarriorsViewController ()<WarriorDetailsViewControllerDegegate>// 接受协议
  6 
  7 @end
  8 
  9 @implementation WarriorsViewController{
 10     
 11     NSMutableArray *_warriorsArray;// 数据源
 12 }
 13 
 14 - (void)viewDidLoad {
 15     [super viewDidLoad];
 16     // 创建数组
 17     _warriorsArray = [NSMutableArray arrayWithCapacity:0];
 18     
 19     // 制造数据
 20     Warrior *player1 = [[Warrior alloc] init];
 21     player1.nameStr = @"カカロット";
 22     player1.fightingCapacityStr = [NSString stringWithFormat:@"戦力:%d",FC_Base];
 23     player1.rating = 1;
 24     [_warriorsArray addObject:player1];
 25     
 26     player1 = [[Warrior alloc] init];
 27     player1.nameStr = @"セクシー";
 28     player1.fightingCapacityStr= [NSString stringWithFormat:@"戦力:%d",FC_Base];
 29     player1.rating = 2;
 30     [_warriorsArray addObject:player1];
 31     
 32     player1 = [[Warrior alloc] init];
 33     player1.nameStr = @"ベジータ";
 34     player1.fightingCapacityStr = [NSString stringWithFormat:@"戦力:%d",FC_Base];
 35     player1.rating = 3;
 36     [_warriorsArray addObject:player1];
 37 }
 38 
 39 #pragma mark - Table view data source
 40 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 41 
 42     return 1;
 43 }
 44 
 45 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 46 
 47     return _warriorsArray.count;
 48 }
 49 
 50 // 直接使用属性
 51 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 52 
 53     WarriorCell *cell = [tableView dequeueReusableCellWithIdentifier:@"WarriorCell" forIndexPath:indexPath];
 54     Warrior *player = [_warriorsArray objectAtIndex:indexPath.row];
 55     cell.warriorName.text = player.nameStr;
 56     cell.warriorValues.text = player.fightingCapacityStr;
 57     cell.warriorIcon.layer.masksToBounds = YES;
 58     cell.warriorIcon.layer.cornerRadius = 3.2;
 59     cell.warriorIcon.image = [self imageForRating:player.rating];
 60     return cell;
 61 }
 62 
 63 // 编辑
 64 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
 65     if (editingStyle == UITableViewCellEditingStyleDelete){
 66         // 删除数据
 67         [_warriorsArray removeObjectAtIndex:indexPath.row];
 68         // 删除UI
 69         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
 70     }
 71 }
 72 
 73 #pragma mark - self_defined_methods
 74 // 选取图片
 75 - (UIImage *)imageForRating:(int)rating{
 76 
 77     switch (rating){
 78         case 1: return [UIImage imageNamed:@"11.png"];
 79         case 2: return [UIImage imageNamed:@"22.png"];
 80         case 3: return [UIImage imageNamed:@"33.png"];
 81     }
 82     return nil;
 83 }
 84 
 85 #pragma mark - prepareForSegue
 86 // 当使用 segue 的时候就必须加入此方法
 87 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
 88 
 89     // segue 标识
 90     if([segue.identifier isEqualToString:@"AddWarrior"]){
 91 
 92         WarriorDetailsViewController *wdVC = (WarriorDetailsViewController*)segue.destinationViewController;
 93         wdVC.delegate = self;// 指定代理
 94     }
 95 }
 96 
 97 #pragma mark - <WarriorDetailsViewControllerDegegate>
 98 // 实现代理
 99 - (void)warriorDetailsViewControllerDidCancel:(WarriorDetailsViewController *)controller{
100 
101     [controller dismissViewControllerAnimated:YES completion:nil];
102 }
103 
104 - (void)warriorDetailsViewControllerDidSave:(WarriorDetailsViewController *)controller{
105     [controller dismissViewControllerAnimated:YES completion:nil];
106 }
107 
108 @end

说明:需要给 segue 指定一个 Identifier。因为 parepareForSegu 需要检查 segue 的身份(可能会同时使用多个联线),那么在 storyboard 中将 segue 的 Identifier 设置为 AddWarrior

小结

1 - 为了完成一个联线你需要做的几件事情

① 首先从起始的控件做一条联线到目标场景

② 将这个联线制定一个 Identifier

③ 为目标场景制作一个代理方法

2 - 要实现返回功能必须要使用代理,因为没有反向联线这种东西。当 sugue 启动之后将会创造出一个目标场景的新实例,你当然可以做一个从目标场景回到原始场景的联线,但是结果可能与你希望的大相径庭, 因为它并不会关闭当前场景并返回原始场景,而是会创建一个原始场景的新实例......这种情况会不停循环,知道把内存耗尽为止。请记住 segue 只用于打开新的场景

 

posted on 2017-11-03 14:18  低头捡石頭  阅读(1288)  评论(0编辑  收藏  举报

导航