在目标 c ios 中保留 viewDidLoad 之外的数据

Posted

技术标签:

【中文标题】在目标 c ios 中保留 viewDidLoad 之外的数据【英文标题】:retaining data outside of viewDidLoad in objective c ios 【发布时间】:2015-05-01 07:33:41 【问题描述】:

我知道之前有人问过这个问题,但提供的答案并没有解决我的问题。

例如,我在 viewDidLoad 中有一个非常简单的对象数组:

@implementation MyViewController 
NSArray *tableData;


- (void)viewDidLoad

   [super viewDidLoad];
   tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is"];
   NSLog(@"My Data: %@", tableData);

在 tableView 中使用 cellForRowAtIndexPath 调用

cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];

这工作正常,NSLog 显示我的数组。但是,当我在 viewDidLoad 之外概述 tableData 时,我的数组是 (null)。

我的问题是,当我的数组在 ViewDidLoad 之外指定时,如何使我的数组可用于 tableView?

编辑:这是我的具体代码:

#import <UIKit/UIKit.h>
#import "PhotoView.h"
@interface FrontViewController : UIViewController

@property (nonatomic, retain) UITableView *tableView;

@end

#import "FrontViewController.h"
#import "StreamScreen.h"
#import "API.h"
#import "PhotoView.h"
#import "StreamPhotoScreen.h"
#import "PrivateViewController.h"
#import "SWRevealViewController.h"
#import "PhotoScreen.h"
#import "RearViewController.h"
#import "SimpleTableCell.h"



@interface FrontViewController()

// Private Methods:
- (IBAction)pushExample:(id)sender;

@end

@implementation FrontViewController
    NSArray *tableData;



#pragma mark - View lifecycle


- (void)viewDidLoad

    [super viewDidLoad];

    self.title = NSLocalizedString(@"Front View", nil);

    SWRevealViewController *revealController = [self revealViewController];

    [self.navigationController.navigationBar addGestureRecognizer:revealController.panGestureRecognizer];

    UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reveal-icon.png"]
                                                                     style:UIBarButtonItemStyleBordered target:revealController action:@selector(revealToggle:)];

    self.navigationItem.leftBarButtonItem = revealButtonItem;

    // This works if I uncomment
    //tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is", nil];

    [self refreshStream];






-(void)refreshStream 
    // call the "stream" command from the web API
    [[API sharedInstance] commandWithParams:
     [NSMutableDictionary dictionaryWithObjectsAndKeys:@"stream", @"command", nil]
                           onCompletion:^(NSDictionary *json) 
                               //got stream

                               [self showStream:[json objectForKey:@"result"]];
                               NSMutableArray *myData = [[NSMutableArray alloc] init];
                               myData = [json objectForKey:@"result"];
                               NSArray *userNameData = [myData valueForKey:@"username"];


                               [self loadData];

                               tableData = userNameData;


                               [self.tableView reloadData];
                               // I can see my json array in NSLog
                               NSLog(@"here's the results: %@", tableData);
                           ];


//This doesn't work either
//-(void)loadData 

    // Add the data to your array.
    //tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is", nil];
    //NSLog(@"My Data: %@", tableData);

   // Now load the table view.
  //  [self.tableView reloadData];
//


-(void)showStream:(NSArray*)stream 

    for (int i=0;i<[stream count];i++) 
        NSDictionary* photo = [stream objectAtIndex:i];


    
    NSArray *checkData = [stream valueForKey:@"username"];
    //I can see my data in NSLog
    NSLog(@"here's the results: %@", checkData);


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    return [tableData count];


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    return 78;



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *simpleTableIdentifier = @"SimpleTableCell";

    SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];


    cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
    cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
    cell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];

    return cell;


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    NSLog(@"didSelectRowAtIndexPath");
    /*UIAlertView *messageAlert = [[UIAlertView alloc]
 initWithTitle:@"Row Selected" message:@"You've selected a row" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];*/
UIAlertView *messageAlert = [[UIAlertView alloc]
                             initWithTitle:@"Row Selected" message:[tableData objectAtIndex:indexPath.row] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

    // Display the Hello World Message
    [messageAlert show];

    // Checked the selected row
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;

    [tableView deselectRowAtIndexPath:indexPath animated:YES];


- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath

    NSLog(@"willSelectRowAtIndexPath");
    if (indexPath.row == 0) 
        return nil;
     

   return indexPath;

@end

【问题讨论】:

所以您基本上是在问如何将变量/等分配给 viewDidLoad 之外的数组?如果是这样的话,只需制作自己的方法并使用它。 "当它在 ViewDidLoad 之外指定时",您是否要在整个应用程序中全局访问数据。 这个数据也可以在外面使用,如果你的tableview没有用需要的单元格显示这个值,你可能在viewDidLoad方法初始化后忘记了UITableviewreloadData。跨度> 请显示数组为(null)的代码 我已经编辑了我的问题以显示我的确切代码。谢谢。 【参考方案1】:
-(void)refreshStream 
    // call the "stream" command from the web API
    [[API sharedInstance] commandWithParams:
        [NSMutableDictionary dictionaryWithObjectsAndKeys:@"stream", @"command", nil] 
        onCompletion:^(NSDictionary *json) 
            //got stream

            [self showStream:[json objectForKey:@"result"]];
            NSMutableArray *myData = [json objectForKey:@"result"];
            NSArray *userNameData = [myData valueForKey:@"username"];
    ];

    tableData = userNameData;

    [self.tableView reloadData]; 

您在这里陷入了异步编程的一个非常常见的陷阱。

commandWithParams 接受一个完成块,您可以在该块中从 JSON 中获取数据。在 API 调用返回之前,不会执行此块。运行此代码时发生的事件顺序是:

    commandWithParams 被调用 tableData 被分配给 userNameData 的内容(大概你也在其他地方声明过,否则这甚至不会编译) reloadData 被调用 ....时间流逝 执行完成块并将 JSON 读入局部变量,然后立即销毁。

您需要将两行(上面列表中的第 2 点和第 3 点)移入完成块。在块返回之前,您的表将没有数据。

【讨论】:

天哪!我没想到。所以问题是@Amy 正在异步加载数据,所以当她调用 tableview 重新加载时,数据实际上还没有准备好。所以只有一件事,当异步加载数据时,他们必须确保负责将数据放入 tableview 的方法必须在异步方法块的末尾调用,而不是在其他位置调用?? 我尝试将 2 和 3 放入块中,但仍然出现空白屏幕。也许我在第 2 点上遗漏了一些东西。你能提供一些示例代码吗?当我尝试简单地提出第 2 点时 tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is"];它仍然返回一个空白屏幕。当我使用 tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is"];在 ViewDidLoad 中。谢谢 @Amy 因为 jrturton 忘了告诉你,除了使用他的解决方案,你需要初始化 NSMutableArray,否则它不会存储任何数据。这样做:NSMutableArray *myData = [[NSMutableArray alloc] init]; myData = [json objectForKey:@"result"]; 你确定从那个 JSON 数组中得到了一些东西吗?如果该数组为空,那将是预期的结果。如果你把你的 hello - my - name - is code 放在完成块中,它在那里工作吗?在完成块内放置断点并检查您看到的值。 @Dan,不,没必要。如果你在做[myData addObject:],你只需要这样做。【参考方案2】:

好吧,我对您的问题的理解是,您想以另一种方法(不是 viewDidLoad)将变量分配给您的 NSArray,然后加载表格视图。

这很简单,只需创建一个负责将数据添加到数组中的方法,然后像这样重新加载表格视图:

-(void)viewDidLoad 
    [super viewDidLoad];

    // Call your method.
    [self loadData];


-(void)loadData 

    // Add the data to your array.
    tableData = [NSArray arrayWithObjects:@"Hello", @"My", @"Name", @"Is"];
    NSLog(@"My Data: %@", tableData);

    // Now load the table view.
    [myTableView reloadData];

更新 1

如果您能与我们分享您的代码,将会更有帮助。当它被调用/等时,你如何设置你的 tableview ......

更新 2

好吧,你的问题似乎很明显。您的表格视图永远不会像那样加载。需要在cellForRowAtIndexPath方法外调用tableviewreloadData方法。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *simpleTableIdentifier = @"SimpleTableCell";

    SimpleTableCell *cell = (SimpleTableCell *)[self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil) 
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    

    cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
    cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
    cell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];

    return cell;   

所以方法调用[self.tableView reloadData]; 应该只在你的refreshStream 方法中调用。

更新 3

您需要先初始化 NSMutableArray,然后才能向其中添加数据。在你的 refreshStrem 方法中初始化它,如下所示:

-(void)refreshStream 

    // call the "stream" command from the web API
    [[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:@"stream", @"command", nil] onCompletion:^(NSDictionary *json) 
    //got stream

        [self showStream:[json objectForKey:@"result"]];

        NSMutableArray *myData = [[NSMutableArray alloc] init];
        myData = [json objectForKey:@"result"];

        NSArray *userNameData = [myData valueForKey:@"username"];
    ];

    tableData = userNameData;
    [self.tableView reloadData];

更新 4

好吧,在阅读@jrturton 的答案后,我认为可以肯定地认为我的答案是垃圾。对于阅读我的答案的任何人,请查看@jrturton 帖子。

【讨论】:

我已经用我的确切代码编辑了我的问题。谢谢。 @Amy 不错,但还不是很有用。您能否更新您的问题以向我们展示您将数组中的元素添加到表格视图的位置。我怀疑您将数据插入到 tableview 的方式有问题。 @Amy 我有点希望您能与我们分享您的cellForRowAtIndexPath 方法。这是您将数组中的数据实际添加到表格视图的方法。 当数据在 viewDidLoad 中时,我的表确实会加载,但这似乎不会导致问题。 @Amy 你应该cellForRowAtIndexPath方法中调用[self.tableView reloadData];【参考方案3】:

嗯,我觉得很害羞。答案很简单。我对 Json 和 API 太着迷了,以至于我没有检查基础知识。我需要的只是在我的 .h 文件中:

@property (strong, nonatomic) IBOutlet UITableView *tableView;

我原来有:

@property (nonatomic, retain) UITableView *tableView;

【讨论】:

这还不是您所需要的 :) 其他更改也很重要!很高兴您现在可以使用它!

以上是关于在目标 c ios 中保留 viewDidLoad 之外的数据的主要内容,如果未能解决你的问题,请参考以下文章

从 swift 文件发送通知并在 ios 的目标 c 文件中接收

如何从 viewcontroller viewdidload 方法触发视图中的功能 - 目标 c - iphone

animateWithDuration 在 vi​​ewWillAppear ios 9 目标 c 中不起作用

在通过 segue 更改视图之前检查并验证 JSON 数据字符串(iOS 应用程序 - 目标 C)

目标 C 和 ARC

在 nib 文件中使用安全区域布局,但将部署目标保留为 iOS 8