prepareForSegue在Button动作之前执行

时间:2016-04-05 23:40:14

标签: ios json uitableview segue viewcontroller

我是IOS的新手并试图解决这个问题。

我正在尝试将json数据从一个View控制器传递给其他(TableViewcontroller),我希望在prepareForSegue方法(然后传递我从按钮获取的json数据)之前执行按钮操作(这有json数据)动作)到TableViewcontroller。

但是我的preparesegue方法首先在按钮操作和tableview没有数据之前执行?

但是当我第二次点击按钮时,我得到了tableview json数据。

当我尝试将Textfield传递给URl时,如果我使用直接URL,则会发生这种情况。

有人可以帮帮我。 如果还有其他方法可以让我知道。

以下是第一个VC中的代码:

- (IBAction)buttonShow:(id)sender {

NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [NSString stringWithFormat:@"Some API URL=%@",self.ingredientTextfield.text];

NSURL *url = [[NSURL alloc]initWithString:urlString];
req = [[NSMutableURLRequest alloc]initWithURL:url];

NSURLSessionDataTask *datatask = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSString *rcCount = [json objectForKey:@"count"];
    NSLog(@"Recipe Count : %@",rcCount);
    NSMutableDictionary *recipedata = [json objectForKey:@"recipes"];
    NSLog(@"Recipe data : %@",recipedata);


    NSMutableArray *titlearray = [[NSMutableArray alloc]init];
    for (NSMutableDictionary *singlerecipedata in recipedata) {
        NSString *title = [singlerecipedata objectForKey:@"title"];
        NSLog(@"Recipe title : %@",title);
        [titlearray addObject:title];
        NSLog(@"tittlearray : %@",titlearray);

    }
    actualDataArray = [[NSArray alloc]initWithArray:titlearray];

    NSLog(@"tittle array inside for:%@",actualDataArray);

}];
NSLog(@"tittle array outside :%@",actualDataArray);

[datatask resume];
[self performSegueWithIdentifier:@"segueIdentifier" sender:sender];  

}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if  ([[segue identifier] isEqualToString:@"segueIdentifier"]) {

        RecipesTableViewController *new = [segue destinationViewController];
        NSLog(@"in segue :%@",actualDataArray);
        [new setMyrecipeTittleArray:actualDataArray];
    }

}

3 个答案:

答案 0 :(得分:1)

准备你的For循环之间的Segue,然后使用Breakpoints你可以检查结果!!

您的密码必须是:

- (IBAction)buttonShow:(id)sender {

NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [NSString stringWithFormat:@"Some API URL=%@",self.ingredientTextfield.text];

NSURL *url = [[NSURL alloc]initWithString:urlString];
req = [[NSMutableURLRequest alloc]initWithURL:url];

NSURLSessionDataTask *datatask = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSString *rcCount = [json objectForKey:@"count"];
    NSLog(@"Recipe Count : %@",rcCount);
    NSMutableDictionary *recipedata = [json objectForKey:@"recipes"];
    NSLog(@"Recipe data : %@",recipedata);


    NSMutableArray *titlearray = [[NSMutableArray alloc]init];
    for (NSMutableDictionary *singlerecipedata in recipedata) {
        NSString *title = [singlerecipedata objectForKey:@"title"];
        NSLog(@"Recipe title : %@",title);
        [titlearray addObject:title];
        NSLog(@"tittlearray : %@",titlearray);

    }
    actualDataArray = [[NSArray alloc]initWithArray:titlearray];
[self performSegueWithIdentifier:@"segueIdentifier" sender:sender];  
    NSLog(@"tittle array inside for:%@",actualDataArray);

}];
NSLog(@"tittle array outside :%@",actualDataArray);

[datatask resume];

}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if  ([[segue identifier] isEqualToString:@"segueIdentifier"]) {

        RecipesTableViewController *new = [segue destinationViewController];
        NSLog(@"in segue :%@",actualDataArray);
        [new setMyrecipeTittleArray:actualDataArray];
    }

}

答案 1 :(得分:0)

如果在IBAction buttonTapped:(id)sender方法中调用performSegueWithIdentifier方法,则必须在调用buttonTapped后调用prepareForSegue。举个例子,看看这段代码:

#import "ViewController.h"

@interface ViewController ()

- (IBAction)goButtonTapped:(id)sender;
@property (weak, nonatomic) IBOutlet UIButton *buttonButton;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSLog(@"PrepareForSegue called");
}

- (IBAction)goButtonTapped:(id)sender {

    NSLog(@"Button tapped %@", [sender description]);
    [self performSegueWithIdentifier:@"SegueToTabs" sender:nil];

}
@end

这会在控制台中产生以下消息:

2016-04-05 21:41:46.300 GUITesting[67708:5496161] Button tapped <UIButton: 0x7fbd4411f010; frame = (20 62; 374 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fbd4411b2f0>>
2016-04-05 21:41:46.304 GUITesting[67708:5496161] prepareForSegue called

所以也许你在代码中做了其他事情,导致你的prepareForSegue在你的buttonTapped之前被调用。

顺便说一句,如果你想在prepareForSegue中将一些对象发送到下一个VC,你可以简单地将它设置为prepareForSegue方法中targetVC的一个属性。

答案 2 :(得分:0)

这种情况正在发生,因为NSURLSessionDataTask异步。因此,在您调用的时间点不会检索数据:

[self performSegueWithIdentifier:@"segueIdentifier" sender:sender]; 

为了更清楚地解释事情,这是一系列事件:

  1. &#34;启动HTTP请求&#34;:[datatask resume];
  2. &#34;执行segue&#34;:[self performSegueWithIdentifier:@"segueIdentifier" sender:sender];
  3. 然后在稍后的回调/完成块中下载您的数据:

    NSMutableArray *titlearray = [[NSMutableArray alloc]init];
    for (NSMutableDictionary *singlerecipedata in recipedata) {
        // ...
    } 
    actualDataArray = [[NSArray alloc]initWithArray:titlearray];
    
  4. ...此时你的segue已经完成。

    要解决此问题,您可以执行以下两项操作之一:

    我首选的方法,因为感觉对用户来说更快(虽然实施起来更具挑战性):

    1. 在主视图控制器上实现委托协议和方法,以在数据任务完成时通知子(表)
    2. 实施某种加载指标(例如UIActivityIndicator
    3. 让孩子(桌子)成为主人的代表
    4. 调用委托方法时,让孩子自行更新(例如[tableView reloadData]
    5. 这具有立即执行segue的好处,这对用户来说感觉更快,并且异步(非阻塞地)在可用时呈现数据。您甚至可以超级光滑并实施一些错误检查,并在数据加载失败或网络超时时显示无法通知。

      另一种方式,更容易实施,但有一些主要缺点:

      performSegue调用移到数据任务的完成块中:

      NSMutableArray *titlearray = [[NSMutableArray alloc]init];
      for (NSMutableDictionary *singlerecipedata in recipedata) {
          // ...
      } 
      actualDataArray = [[NSArray alloc]initWithArray:titlearray];
      [self performSegueWithIdentifier:@"segueIdentifier" sender:sender];
      

      这样做的最大缺点是对用户来说会感觉很慢。即使连接很好,现在可能在按下按钮和执行segue之间有100-500ms的延迟。在缓慢或无响应的网络连接上,segue可能不会执行几秒钟。这使用户感到沮丧。