Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 从WatchKit中的模式视图传回数据_Ios_Watchkit_Apple Watch - Fatal编程技术网

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中即可

命中注定