【问题标题】:Manage Multiple ViewControllers from a TableView从 TableView 管理多个 ViewController
【发布时间】:2011-06-28 01:11:34
【问题描述】:

我很好奇是否有人有从 TableView 管理多个 ViewController 的想法。我在 TableView 中显示了大约七个项目的列表,每个项目都有一个专用的 ViewController。我的第一个想法是用各种 ViewController 初始化一个数组。

NSMutableArray *viewControllers = [[NSMutableArray alloc] initWithCapacity:7];
[viewControllers addObject:[[ViewController1 alloc] initWithNibName:@"View1" bundle:nil]];
[viewControllers addObject:[[ViewController2 alloc] initWithNibName:@"View2" bundle:nil]];
...

然后引用该数组以加载有关项目选择的适当视图。

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [self.navigationController pushViewController:[viewControllers objectAtIndex:indexPath.row] animated:YES];
}

我真的不确定这是否合适。任何方向都会很棒。

已编辑:

根据 Ryan 和 Joe 的反馈,我实现了一个对象来保存我的表格项目。缩写我的问题也引起了对实现细节的一些混淆。添加了管理视图控制器和选择标签栏项目的完整解决方案。

TableNavigationItem.h

#import 


@interface TableNavigationItem : NSObject {
    NSString *title;
    NSNumber *tabIndex;
    id viewController;
}

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSNumber *tabIndex;
@property (nonatomic, retain) id viewController;

@end

TableNavigationItem.m

#import "TableNavigationItem.h"


@implementation TableNavigationItem

@synthesize title;
@synthesize viewController;

- (id) init{

    if(self = [super init]){
        self.title = @"";
    }

    return self;
}

- (void) dealloc {
    [title release];
    [tabIndex release];
    [viewController release];
    [super dealloc];
}

@end

然后按照 Joe 的建议进行初始化。

NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:7];
TableNavigationItem *navItem;

// view 1
navItem = [[TableNavigationItem alloc] init];
navItem.title = @"View 1";
navItem.tabIndex = [NSNumber numberWithInt:1];
[mutableArray addObject:navItem];
[navItem release];

// view 2
navItem = [[TableNavigationItem alloc] init];
navItem.title = @"View 2";
navItem.viewController = [ViewController2 class]];
[mutableArray addObject:navItem];
[navItem release];

...

// store the navigation items
self.tableItems = [NSArray arrayWithArray:mutableArray];
[mutableArray release];

然后

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    TableNavigationItem *navItem = [tableItems objectAtIndex:indexPath.row];
    if(navItem.viewController != nil){
        [self.navigationController pushViewController:[[[navItem.viewController alloc] init] autorelease] animated:YES];
    }
    else if(navItem.tabIndex != nil){
        [((MyAppDelegate *)[UIApplication sharedApplication].delegate).tabBarController setSelectedIndex:[navItem.tabIndex integerValue]];
    }
}

【问题讨论】:

  • 我不确定我是否理解 TableNavigationItem 的意义。为什么不在ViewController1ViewController2 上创建title 方法?那么你的数组可以是:viewControllers=[NSArray arrayWithObjects:[ViewController1 class], [ViewController2 class], nil] 而你的tableView:didSelectRowAtIndexPath: 可以简单地调用[self.navigationController pushViewController:[[[[viewControllers objectAtIndex:indexPath.row] alloc] init] autorelease] animated:YES]
  • 另外,如果tableItems 是保留属性,则copy 调用将导致泄漏,除非您自动释放该结果数组。但是你总是可以只分配给 NSMutableArray(谁会知道区别?),让它成为 [NSMutableArray arrayWithCapacity:7] 或者更好的是 -[NSMutableArray arrayWithObjects:..., nil]!它还可以帮助您了解 Cocoa 的内存管理和对象生命周期。
  • +1 如前所述,TableNavigationItem 有点多余。我删除了一些用例以简化问题(我有一些导航项可以导航标签栏控制器)。我想我应该提出整个问题。
  • +1 你是对的。我没有意识到副本增加了保留计数(我很少使用它)。

标签: iphone uitableview uiviewcontroller


【解决方案1】:

如果这些控制器管理的所有视图都立即在屏幕上可见,那么这种方法没有任何问题。确保释放-viewDidUnload 中的VC 数组,并在-viewDidLoad 中重新创建它,这样运行时可以在下一个视图被推送到屏幕时卸载所有这些额外的对象。请注意,只有根视图控制器会接收视图生命周期事件;您创建的视图控制器并手动将拥有的视图添加到表中不会调用这些方法。您必须通过通知或委托实现一些管道,以将这些视图生命周期事件放入“子视图”。

您的问题的最佳答案是“使用它”。至少运行 Allocations 和 VM 工具,并检查这些视图控制器消耗了多少内存。如果您想通过 Instruments 提高您的技能,请观看 WWDC 2011 的 Performance session,他们在教授如何使用它来查找内存和性能问题方面做得很好。

【讨论】:

  • 谢谢瑞恩。先检查答案。
【解决方案2】:

这对我来说听起来不错。我唯一担心的是您的视图控制器是否占用大量内存,在这种情况下您可能需要做出决定:预先分配所有内容是否更好(即您确定可以将所有这些控制器的状态都放入可用内存中吗? ?) 还是根据需要加载适当的视图控制器更好?

看起来您的 ViewController 属于不同的类。如果是这种情况(并且如果每个人总是使用相同的相应笔尖),我会考虑在每个人身上实现一个自定义 -init 方法,并使您的选择数组成为 Class 对象之一。不过,这只是个人喜好问题。

还有一件事:您需要自动释放这些视图控制器,否则无论如何都会泄漏内存。

【讨论】:

  • 你为什么要自动释放视图控制器 - 一旦数组被释放,任何不属于视图层次结构的控制器都会被释放。如果您改为自动释放它们,那么即使在阵列被释放后,所有控制器仍将保留在内存中,直到设备遇到内存压力或池被耗尽。
  • 上面的代码使用了[viewControllers addObject:[[ViewController1 alloc] initWithNibName:@"View1" bundle:nil]]; 和一个数组。这使控制器的 retainCount 已经为 2,当它被推送时为 3(对吗?)。当 VC 被弹出时,这是 -1,当数组被释放时,这是另一个 -1,然后我们仍然有 1 浮动。至少在桌面上,自动释放池非常频繁地耗尽 afaik。
  • 澄清一下,我是说那些初始化行应该是:[viewControllers addObject:[[[VCClass alloc] initWithNibName...] autorelease]].
  • 谢谢乔。为自动释放提示 +1。
  • @joe 是对的,我误读了代码。由于您直接在 addObject: 方法中初始化控制器,因此您必须自动释放它们。如果您想遵循稍微严格的内存管理规则,这可能会或可能不会影响内存使用,您可以先创建控制器(在局部变量中),将它们添加到数组中,然后释放控制器。那时,阵列将拥有控制器并在适当的时候释放它们,而不是依赖自动释放池来耗尽。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多