使用 block 和 segue 从 watchOS interfaceController 传回数据
在 interfaceControllers 之间来回传递数据并不是那么简单。WatchKit 中有 segue 进程,但第一个问题是没有 prepareForSegue 并且您无法到达 segue 的destinationViewController,因此您无法轻松地将东西注入新控制器(WatchOS 3 - 4)。在向后的方向没有出口,所以你无法到达放松的segue。
另一个问题是这些解决方案尝试更新 willActivate 方法中第一个 interfaceController 的数据和用户界面,该方法在手表屏幕唤醒时触发 - 非常频繁 - 这可能会导致问题并且很复杂。
正如上面的答案所描述的,编程实践主要是使用委托和使用segue的上下文注入自我。
但是使用委托有点复杂,所以我使用更现代的块,我认为更好更优雅。
让我们看看如何:
首先让我们在 Apple Watch 故事板的 Interface Builder 中准备 segue,只需将一个按钮连接到另一个 interfaceController 按下 Ctrl 按钮并命名 segue。

然后在源 interfaceController 的 .h 文件中,我们将其命名为SourceInterfaceController.h为该块声明一个属性:
@property (nonatomic, strong) BOOL (^initNewSessionBlock)(NSDictionary *realTimeDict, NSError *error);
然后使用contextForSegueWithIdentifier:如果您有更多 segue,则使用segueIdentifier将块或任何其他数据传输到目标 interfaceController 。
这个 Apple 方法实际上使用 (id)context 作为返回对象,它可以是任何对象,并且目标 interfaceController 的awakeWithContext:(id)context方法将在 interfaceController 启动时使用它。
因此,让我们在SourceInterfaceController.m中声明该块,然后将其传递给上下文:
- (id)contextForSegueWithIdentifier:(NSString *)segueIdentifier {
__unsafe_unretained typeof(self) weakSelf = self;
if ([segueIdentifier isEqualToString:@"MySegue"]) {
self.initNewSessionBlock = ^BOOL (NSDictionary *mySegueDict, NSError *error)
{
[weakSelf initNewSession];
NSLog(@"message from destination IC: %@", realTimeDict[@"messageBack"]);
return YES;
};
return self.initNewSessionBlock;
}
else if ([segueIdentifier isEqualToString:@"MyOtherSegue"]) {
self.otherBlock = ^BOOL (NSString *myText, NSError *error)
{
//Do what you like
return YES;
};
return self.otherBlock;
}
else {
return nil;
}
}
如果您想将更多的数据传输到目标 interfaceController,而不仅仅是带有上下文的块,只需将它们包装在 NSDictionary 中。
在目标 interfaceController 中命名为DestinationInterfaceController.h让我们声明另一个属性来使用任何名称但相同的变量声明来存储块
@property (copy) BOOL (^initNewSessionBlock)(NSDictionary *realTimeDict, NSError *error);
然后从DestinationInterfaceController.m的上下文中获取块:
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
self.initNewSessionBlock = context;
}
稍后在DestinationInterfaceController.m中只需触发块,例如在带有按钮的操作方法中:
- (IBAction)initNewSessionAction:(id)sender {
NSError *error = nil;
NSDictionary *realTimeDict = @{@"messageBack" : @"Greetings from the destination interfaceController"};
BOOL success = self.initNewSessionBlock(realTimeDict, error);
if (success) {
[self popController];
}
}
该块将使用目标 interfaceController 范围内的数据执行源 interfaceController 的任何方法,因此您可以将数据发送回目标 sourceController。如果一切正常,您可以使用popController弹出 interfaceController并且块返回 yes 作为 BOOL。
注意:当然你可以使用任何类型的 segue,无论是push还是modal,你也可以使用pushControllerWithName:context:来触发 segue,你也可以以同样的方式使用这个方法的 context。