我是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];
}
}
答案 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];
为了更清楚地解释事情,这是一系列事件:
[datatask resume];
[self performSegueWithIdentifier:@"segueIdentifier" sender:sender];
然后在稍后的回调/完成块中下载您的数据:
NSMutableArray *titlearray = [[NSMutableArray alloc]init];
for (NSMutableDictionary *singlerecipedata in recipedata) {
// ...
}
actualDataArray = [[NSArray alloc]initWithArray:titlearray];
...此时你的segue已经完成。
要解决此问题,您可以执行以下两项操作之一:
我首选的方法,因为感觉对用户来说更快(虽然实施起来更具挑战性):
UIActivityIndicator
)[tableView reloadData]
)这具有立即执行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可能不会执行几秒钟。这使用户感到沮丧。