【问题标题】:NSMutableArray gets reset after calling modalViewControllerNSMutableArray 在调用 modalViewController 后被重置
【发布时间】:2012-08-25 12:02:27
【问题描述】:

已由@T-X 解决。我已经在代码中用“// SOLUTION”标记了更改!!!

我有以下问题,如果我展示ModalViewController,NSMutableArray“projectsArray”会被重置。

这是我的代码:

这里是 .h 文件:

    // ViewController.h
#import <UIKit/UIKit.h>

@class AddProject;

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
    IBOutlet UITableView *projectsTableView;
    UIAlertView *reallyDelete;

    BOOL candelButtonClicked;
    NSIndexPath *actualIndexPath;

    NSMutableArray *projectsArray;
    NSInteger ID;
    NSString *NAME;

    AddProject *addProject;
    **ViewController *viewContr; // SOLUTION**
}
- (IBAction)addNewProject:(id)sender;

- (void)addToTableView:(NSString *)projectName;

@property (nonatomic, retain) UIAlertView *reallyDelete;
@property (nonatomic) NSInteger cancelButtonIndex;

@property IBOutlet UITableView *projectsTableView;

@property (nonatomic, retain) AddProject *addProject;
**@property (nonatomic, retain) ViewController *viewContr; // SOLUTION**

@end

这里是 .m 文件:

    // ViewController.m
#import "ViewController.h"
#import "CustomTableCell.h"
#import "AddProject.h"

@interface ViewController ()

@end

@implementation ViewController

**@synthesize viewContr; // SOLUTION**

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

    projectsArray = [[NSMutableArray alloc] init];
    ViewController *element = [[ViewController alloc] init];

    element->ID = 1;
    element->NAME = @"Demo project";
    NSLog(@"viewdidload");
    [projectsArray addObject:element];

    NSLog(@"1. Array length: %d", [projectsArray count]);
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if ([projectsArray count] < 1) {
        NSLog(@"2. Array length: 0");
        return 0;
    } else {
        NSLog(@"2. Array length: %d", [projectsArray count]);
        return [projectsArray count];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 78;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *customTableCellIdentifier = @"CustomTableCell";

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

    ViewController *element = [[ViewController alloc] init];
    element = [projectsArray objectAtIndex:indexPath.row];
    cell.nameLabel.text = element->NAME;
    cell.prepTimeLabel.text = [NSString stringWithFormat:@"%i", element->ID];

    NSLog(@"3. Array length: %d", [projectsArray count]);

    return cell;
}

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

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source

        reallyDelete = [[UIAlertView alloc] initWithTitle:@"Deleting" message:@"Do your really want to delete that row?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil];
        [reallyDelete show];

        actualIndexPath = indexPath;
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (buttonIndex != [reallyDelete cancelButtonIndex])
    {
        //If "Yes" clicked delete
        [projectsArray removeObjectAtIndex:actualIndexPath.row];
        NSLog(@"delete row");

        [self.projectsTableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObjects:actualIndexPath, nil] withRowAnimation:YES];
        [self.projectsTableView reloadData];
    }
}

#pragma mark Edit

- (IBAction)addNewProject:(id)sender {
    NSLog(@"4. Array length: %d", [projectsArray count]);

    AddProject *addProjectView = [[AddProject alloc] initWithNibName:@"AddProject" bundle:nil];
    NSLog(@"4.1 Array length: %d", [projectsArray count]);
    addProjectView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    NSLog(@"4.2 Array length: %d", [projectsArray count]);
    addProjectView.modalPresentationStyle = UIModalPresentationFormSheet;
    NSLog(@"4.3 Array length: %d", [projectsArray count]);
    **addProjectView.viewContr = self; // SOLUTION**
    [self presentModalViewController:addProjectView animated:YES];
    NSLog(@"4.4 Array length: %d", [projectsArray count]);
    addProjectView.view.superview.frame = CGRectMake(addProjectView.view.center.x/2.5, addProjectView.view.center.y/3, 800, 600);
    NSLog(@"4.5 Array length: %d", [projectsArray count]);
}

- (void)addToTableView:(NSString *)projectName
{
    NSLog(@"Project Array: %@", projectsArray);
    NSLog(@"addToTableView: %@", projectName);    
    NSLog(@"5. Array length: %d", [projectsArray count]);

    ViewController *element = [[ViewController alloc] init];

    element->ID = 2;
    element->NAME = projectName;

    [projectsArray addObject:element];

    NSLog(@"6. Array length: %d", [projectsArray count]);

    [self.projectsTableView reloadData];
    [self.projectsTableView setNeedsDisplay];
}

- (void)viewDidUnload
{
    [self setProjectsTableView:nil];
    self.projectsTableView = nil;
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

@end

这里是模态呈现视图的 .h 文件:

    // AddProject.h
#import <UIKit/UIKit.h>

@class ViewController;

@interface AddProject : UIViewController
{    
    IBOutlet UITextField *projectName;

    ViewController *viewContr;
}

- (IBAction)back:(id)sender;
- (IBAction)next:(id)sender;

@property (nonatomic, retain) ViewController *viewContr;

@end

模态呈现文件的.m文件:

    // AddProject.m
#import "AddProject.h"
#import "ViewController.h"

@interface AddProject ()

@end

@implementation AddProject

**@synthesize viewContr; // SOLUTION I've mist to synthesize it**

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    **// SOLUTION no new allocation/init of ViewController**
}

- (IBAction)back:(id)sender
{
    [self dismissModalViewControllerAnimated:YES];
}

- (IBAction)next:(id)sender
{
    [viewContr addToTableView:projectName.text];
    [viewContr.projectsTableView reloadData];
    [viewContr.projectsTableView setNeedsDisplay];
    [self dismissModalViewControllerAnimated:YES];
}

- (void)viewDidUnload
{
    projectName = nil;
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

@end

我已经使用断点测试了代码,并且可以在 AddProject 类“viewDidLoad”开始加载时找到问题。但我不知道为什么它会重置数组。

【问题讨论】:

    标签: objective-c ipad methods nsmutablearray modalviewcontroller


    【解决方案1】:

    您从ViewController 屏幕导航到Add project 屏幕。在Add Project Screen 中,您添加了一个新项目并希望将此信息委托给您来自的ViewController Screen。

    现在,您正试图在您的 AddProject 中拥有一个 ViewController 的实例,您在 viewDidLoad 方法中新实例化它,当添加项目时,您通过调用 - (void)addToTableView:(NSString *)projectName 向它提供信息. 这不起作用,因为 - 您分配的 ViewController 实例是一个新实例,而不是您从中导航的实例。当您执行alloc + init 时,您会得到一个新对象。因此,尽管您在 ViewController 上调用了 addToTableView:,但它不起作用,因为接收此消息的 ViewController 实例是一个新实例,而不是您从中导航的实例。

    因此,您需要做的就是 - 在您的 Add Project 中有一个 ViewController 属性,您可以在导航之前设置它。然后您可以向此属性发送消息 - 如this 成绩单中所述。

    我想说——不管这个东西是有效的,它提供了两个控制器之间的紧密耦合。

    理想情况下,这可以通过将ViewController(您从哪里导航)作为Add Project(您导航到哪里)的代表来完成。然后Add Project 可以通过- (void) addProjectController:(AddProjectViewController *) controller didAddProject:(NSString *) projectName 之类的方式将添加的项目委托给它的委托。这提供了两个视图控制器之间的丢失耦合。要了解委托概念,请参阅Delegates and Datasources。或者,搜索其他堆栈溢出帖子。

    【讨论】:

      【解决方案2】:

      您应该在视图控制器的 init 方法中分配 projectsArray,而不是在 viewDidLoad 中。 projectsArray = [[NSMutableArray alloc] init]; 在加载视图时分配了一个新的空数组。

      【讨论】:

      • 在viewDidLoad方法中实例化也不错。视图仅加载一次(当请求视图控制器的视图时),并且仅在它们由于内存不足而被卸载时再次加载。在这种情况下,程序员有责任在viewDidUnload 方法或didReceiveMemoryWarning 方法中释放它们,这取决于它是否可以轻松重新创建或其他原因。 viewDidLoad 和 viewDidUnload 是视图生命周期方法的一部分。
      • viewDidLoad 中的分配因此也使您有机会在 viewDidUnload 方法中释放其中的分配,这是一个很好的做法,因为当内存不足时,不需要的分配应该是释放以释放内存。如果你在init 方法中分配,问题是你会在哪里release 在内存不足的情况下重新创建它们?
      • 你是对的,但从问题中我的印象是 projectArray 应该在视图控制器的整个生命周期中持续存在。
      • 是的,它应该持续存在,因为如果它被释放,用户将丢失所有添加的项目。每次加载视图时,他都可以在 viewDidLoad 方法中执行 if(!projectsArray) { // allocate projectsArray ... } 以防止它被分配(并因此丢失以前添加的对象),或者按照您的建议将其移动到 init 方法中。
      【解决方案3】:

      好的,我的问题已通过 stackoverflow 聊天解决。最终解决方案的提示来自用户@T-X。我在问题的代码中添加了提示。它们标有“// SOLUTION”。

      在添加项目视图控制器的 viewDidLoad 方法中,删除该行 viewContr = [[ViewController alloc] init];。现在制作变量 viewContr 在您的 ViewController 类属性中。还合成 它。最后在- (IBAction)addNewProject:(id)sender 方法中, 在展示控制器之前,请执行- addProjectView.viewContr = self;。它会解决你的问题。

      (引用chat.stackoverflow | @T-X)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多