Ios 从WatchKit中的模式视图传回数据
当以模式呈现或推送接口控制器时,我们可以指定Ios 从WatchKit中的模式视图传回数据,ios,watchkit,apple-watch,Ios,Watchkit,Apple Watch,当以模式呈现或推送接口控制器时,我们可以指定上下文参数,将一些数据传递给新控制器,如下所示 // Push [self pushControllerWithName:@"MyController" context:[NSDictionary dictionaryWithObjectsAndKeys:someObject, @"someKey", ..., nil]]; // Modal [self presentControllerWithName:@"MyController" conte
上下文
参数,将一些数据传递给新控制器,如下所示
// Push
[self pushControllerWithName:@"MyController" context:[NSDictionary dictionaryWithObjectsAndKeys:someObject, @"someKey", ..., nil]];
// Modal
[self presentControllerWithName:@"MyController" context:[NSDictionary dictionaryWithObjectsAndKeys:someObject, @"someKey", ..., nil]];
我的问题是,我们如何才能做相反的事情
假设我们提供一个控制器,让用户从列表中选择一个项目,然后返回主控制器,我们如何获取已选择的项目?我编写了一个完整的示例,在WatchKit中使用委派,在上下文中传递委派实例,并从该模式调用委派函数: 下面是示例的principale类: InterfaceController.swift 这是主控制器,视图上有一个标签和一个按钮。按下按钮时,会调用
presentItemChooser
并显示ModalView(ModalInterfaceController)。我将上下文中的InterfaceController
实例传递给modal。重要信息:此控制器实现“ModalItemChooserDelegate”功能(协议定义在模式文件中)
ModalInterfaceController.swift
这是我的模态控制器的类。我持有我以前控制器的引用(self.delegate=context as?InterfaceController
)。当选择一行时,我调用我的委托函数didSelectItem(selectedItem)
,然后将其取消
protocol ModalItemChooserDelegate {
func didSelectItem(itemSelected:String)
}
class ModalInterfaceController: WKInterfaceController {
let rowId = "CustomTableRowController"
let items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]
var delegate: InterfaceController?
@IBOutlet weak var customTable: WKInterfaceTable!
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
self.delegate = context as? InterfaceController
// Configure interface objects here.
println(delegate)
loadTableData()
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
private func loadTableData(){
customTable.setNumberOfRows(items.count, withRowType: rowId)
for(i, itemName) in enumerate(items){
let row = customTable.rowControllerAtIndex(i) as! TableRowController
row.fillRow(itemName)
}
}
override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {
let selectedItem = items[rowIndex]
self.delegate?.didSelectItem(selectedItem)
self.dismissController()
}
}
这就是我将数据传递回上一个控制器的方式。如果有更好的方法,请告诉我,我会接受的。:) 正如ghr所说,这需要更多的解释。简单的(如果有黑客攻击的话)方法是使呈现控制器成为您要传递到呈现控制器的上下文的一部分。这样,您可以在需要时回拨演示控制器。一种方法是使用NSDictionary作为上下文,并存储一个带有对呈现控制器的引用的特殊键。希望这能有所帮助。我一直在测试将
self
传递给控制器(模态或非模态),并使用diddactivate
作为调用委托方法的一种方式,但问题是,每当屏幕关闭或出现新视图时,都会调用它。我刚刚开始使用WatchKit,所以我可能完全错了
我的代表
@class Item;
@class ItemController;
@protocol AddItemDelegate <NSObject>
- (void)didAddItem:(ItemController *)controller withItem:(Item *)item;
@类项目;
@类项控制器;
@协议附加代理
-(void)didAddItem:(ItemController*)controller with Item:(Item*)Item;
我的根控制器
@interface ListController() <AddItemDelegate>
...
- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex {
// TODO: How do we pass data back? Delegates? Something else?
if ([self.items[rowIndex] isEqualToString:@"Item 1"]) {
// TODO: Do I really want to pass along a single object here?
[self pushControllerWithName:@"Item" context:self];
}
}
...
#pragma mark - AddItemDelegate
- (void)didAddItem:(ItemController *)controller withItem:(Item *)item {
NSLog(@"didAddItem:withItem: delegate called.");
}
@property (nonatomic, strong) Item *item;
@property (nonatomic, weak) id<AddItemDelegate> delegate;
...
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// TODO: Check that this conforms to the protocol first.
self.delegate = context;
}
...
- (void)didDeactivate {
[super didDeactivate];
[self.delegate didAddItem:self withItem:self.item];
}
@接口ListController()
...
-(void)table:(WKInterfaceTable*)table didSelectRowAtIndex:(NSInteger)rowIndex{
//TODO:我们如何传回数据?委托?其他什么?
if([self.items[rowIndex]isEqualToString:@“Item 1”]){
//TODO:我真的想在这里传递一个对象吗?
[self-pushControllerWithName:@“项”上下文:self];
}
}
...
#pragma标记-AddItemDelegate
-(void)didAddItem:(ItemController*)controller with Item:(Item*)Item{
NSLog(@“didAddItem:withItem:delegate called.”);
}
我的孩子控制器
@interface ListController() <AddItemDelegate>
...
- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex {
// TODO: How do we pass data back? Delegates? Something else?
if ([self.items[rowIndex] isEqualToString:@"Item 1"]) {
// TODO: Do I really want to pass along a single object here?
[self pushControllerWithName:@"Item" context:self];
}
}
...
#pragma mark - AddItemDelegate
- (void)didAddItem:(ItemController *)controller withItem:(Item *)item {
NSLog(@"didAddItem:withItem: delegate called.");
}
@property (nonatomic, strong) Item *item;
@property (nonatomic, weak) id<AddItemDelegate> delegate;
...
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// TODO: Check that this conforms to the protocol first.
self.delegate = context;
}
...
- (void)didDeactivate {
[super didDeactivate];
[self.delegate didAddItem:self withItem:self.item];
}
@属性(非原子,强)项*项;
@属性(非原子,弱)id委托;
...
-(void)唤醒上下文:(id)上下文{
[super awakeWithContext:context];
//TODO:首先检查它是否符合协议。
self.delegate=上下文;
}
...
-(无效)无效{
[超级迪迪];
[self.delegate添加项:self with item:self.item];
}
您可以通过在上下文中传递self
通过协议传回信息:
- (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.m
// don't forget to conform to the protocol!
@interface InterfaceController() <PictureSelectionControllerDelegate>
//...
// in some method
[self pushControllerWithName:@"PictureSelectionController"
context:@{@"delegate" : self}];
@property (nonatomic, unsafe_unretained) id<PictureSelectionControllerDelegate> delegate;
// ...
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
if ([context isKindOfClass:[NSDictionary class]]) {
self.delegate = [context objectForKey:@"delegate"];
}
}
并在InterfaceController.m
中的委托方法中接收它:
- (IBAction)buttonTapped {
// get image
UIImage *someCrazyKatPicture = //...
[self.delegate seletedPicture:someCrazyKatPicture];
}
- (void)selectedPicture:(UIImage *)picture {
NSLog(@"Got me a cat picture! %@", picture);
}
也许还有其他方法,但我更喜欢使用pushControllerWithName:method 根控制器:
- (IBAction)GoToChildControllerButton {
[self pushControllerWithName:@"TableInterfaceController" context:@"pass some data to child controller here..."];
}
- (IBAction)BackToRootControllerButton {
[self pushControllerWithName:@"TableInterfaceController" context:@"pass some data back to root controller here..."];
}
子控制器:
- (IBAction)GoToChildControllerButton {
[self pushControllerWithName:@"TableInterfaceController" context:@"pass some data to child controller here..."];
}
- (IBAction)BackToRootControllerButton {
[self pushControllerWithName:@"TableInterfaceController" context:@"pass some data back to root controller here..."];
}
使用block和segue将数据从watchOS interfaceController传回
在InterfaceController之间来回传递数据并不是那么简单。WatchKit中有segue进程,但第一个问题是没有prepareForSegue,您无法访问segue的destinationViewController,因此无法轻松地将内容注入新控制器(WatchOS 3-4)。
在后退方向上没有出口,因此无法到达展开段
另一个问题是,这些解决方案试图更新willActivate方法中第一个interfaceController的数据和用户界面,该方法在手表屏幕唤醒时随时触发-非常频繁-这可能会导致问题和复杂
正如上面的答案所描述的,编程实践主要是使用segue的上下文委托和注入self
但使用委托有点复杂,所以我使用了更现代的块,我认为更好更优雅
让我们看看如何:
首先,让我们在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)上下文作为返回对象,它可以是任何对象,并且目标interfaceController的awakeWithContext:(id)上下文方法将在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中即可
命中注定