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 只用于打开新的场景
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)