Objective-C:访问其他UIViewControllers中的对象的问题
所以我有一个自定义的UITableViewCell,它持有对其包含视图控制器(VC中有其表)的引用。
// MyCell.h #import <UIKit/UIKit.h> #import "RootViewController.h" @interface MyCell : UITableViewCell @property (nonatomic, strong) IBOutlet RootViewController *rootViewController; -(IBAction)checkBoxClicked:(UIButton*)sender; // MyCell.m @implementation MyCell @synthesize rootViewController = _rootViewController; -(IBAction)checkBoxClicked:(UIButton*)sender { [self setCheckBoxChecked:!_checkBoxChecked]; [_rootViewController refreshVisibleViewForCellTagged:self.tag]; }
在我的单元格中,我有一个button来改变一个variables,然后在我的rootViewController中调用一个函数。 这个方法实际上是调用的,但是当我试图访问任何对象的时候,它们是'0x0'/ nil的refreshVisibleViewForCellTagged方法里面的RootViewController。
// RootViewController.h @interface RootViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, strong) IBOutlet UITableView *myTableView; // RootViewController.m - (void) refreshVisibleViewForCellTagged:(NSInteger)cellTag { UITableView *tableView = self.myTableView; // nil NSIndexPath *indexPath = [self.myTableView indexPathForSelectedRow]; // nil MyCell *selectedCell = (MyCell*)[self.myTableView cellForRowAtIndexPath:indexPath]; // nil if (selectedCell.tag == cellTag) { NSLog(@"Refresh one way."); } else { NSLog(@"Do something else."); } }
任何人都可以阐明为什么我不能从方法'refreshVisibleViewForCellTagged'内部访问RootController中的任何对象/variables?
谢谢,麻烦您了!
**我最大的问题是为什么我不能访问任何对象在视图控制器中调用方法从不同的视图控制器。 有一些伟大的编程的真相,我不知道这里,这是一个权限问题? 我没有使用@class(正向分类)在这种情况下。
正如@trojanfoe所说,代表团是一个更好的办法。 而不是#import "RootViewController.h"
,最好是采用委派。 因为UITableViewCell
是一个孩子, RootViewController
是父视图。 你不想让孩子直接和父母谈话。
-
通过授权:
-
在
MyCell.h
文件中 -
删除
#import "RootViewController.h"
。 -
修改
MyCell.h
如下:
@protocol MyCellDelegate; // if you need to have forward declaration @interface MyCell : UITableViewCell // @property (nonatomic, strong) IBOutlet RootViewController *rootViewController; @property (nonatomic) id <MyCellDelegate> delegate; @end @protocol MyCellDelegate <NSObject> - (void)refreshVisibleViewForCellTagged:(NSInteger)cellTag; @end
- 在
MyCell.m
。
@synthesize delegate; -(IBAction)checkBoxClicked:(UIButton*)sender { [self setCheckBoxChecked:!_checkBoxChecked]; //[_rootViewController refreshVisibleViewForCellTagged:self.tag]; [self.delegate refreshVisibleViewForCellTagged:self.tag]; }
- 在
RootViewController.h
采用MyCell的代理
#import "MyCell.h" @interface RootViewController : UIViewController <MyCellDelegate>
- 在
RootViewController.m
。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = // your implementation //assuming all your cells are of MyCell kind // set RootViewController as the delegate of each cell ((MyCell *)cell).delegate = self; return cell; }
- 在
RootViewController.m
实现委托方法。
- (void)refreshVisibleViewForCellTagged:(NSInteger)cellTag { // whatever you have }
PS上面的代码是为了说明。 我没有运行它们。 如果有些部分不起作用,请告诉我,我会修改它。
RootViewController中的这些对象以您调用的方式为零的原因是因为您没有访问RootViewController的同一个实例。 这是一个不同的(新)实例,因此所有对象都是零。
忽略视图控制器甚至涉及的事实。 你有什么是对象,以一定的模式连接在一起。 在另一个视图控制器中访问数据与访问任何其他对象中的数据没有区别。 视图控制器没有什么“魔力”,除了与其他对象有一些标准的连接。
恕我直言,这是一个糟糕的devise。 对于初学者来说,你的单元格不应该需要一个引用它所在的表的视图控制器(阅读两次,仅仅因为它的概念令人困惑,这几乎没有意义)。 你有一个强烈的参考这个视图控制器。 那么当操作系统试图释放你的视图控制器时会发生什么? 它永远不能够,因为表视图单元格作为一个强大的参考,保持其计数为1.相同的情况也适用于单元格。 你冒险进入保留周期。 一般来说,孩子的观点应该是对父母的弱点。
但这甚至不是真正的父母/子女关系。 我会build议,而不是像这样,这一切都发生在你的视图控制器包含表视图的方法:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // Assuming you set a reuse identifier "cellId" in the nib for your table view cell... MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:@"cellId"]; if (!cell) { // If you didn't get a valid cell reference back, unload a cell from the nib NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"MyCell" owner:nil options:nil]; for (id obj in nibArray) { if ([obj isMemberOfClass:[MyCell class]]) { // Assign cell to obj, and add a target action for the checkmark cell = (MyCell *)obj; [cell.checkMarkButton addTarget:self action:@selector(checkPressed:) forControlEvents:whateverEventYouWant]; break; } } } // Set the tag of the cell here, since we may get a different cell back from the reuse queue cell.checkMarkButton.tag = indexPath.row; return cell; }
现在设置点击复选标记button的方法
- (void)checkPressed:(id)sender { UIButton *checkmark = (UIButton *)sender; // This will give you the row of the checked button int checkedCellRow = checkmark.tag; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:checkedCellRow inSection:0]; // Now you can grab a reference to that cell if you need to MyCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; }
这样,你就可以将所有与控制器有关的东西放在你的控制器类中(例如,如何处理正在按下的复选标记button),而不需要处理引用你的单元格表的视图控制器的这种尴尬。
编辑:我想我也应该帮助回答你的问题…首先,如果你说在你的refreshVisibleViewForCell方法,你得到一个零值self.myTableView,你确定它正确地连接在IB? 即使连接起来,也可以点击小x将其解开并重新连接。 还要确保你已经@synthesized myTableView属性。 没有看到更多的代码,一个国际文凭的问题是我最好的猜测,为什么你得到一个零值tableView。 这里的零值将会导致一个零的indexPath和selectedCell。 至于你的大问题,你可以访问你的视图控制器中的对象的属性 。 那些属性当然可以是对象。 所以在你的例子中,如果你在selectedCell上有一个标签属性,你可以从任何你有对selectedCell的有效引用的地方访问它。 如果selectedCell为零,则该属性将为零。 @class更适合于头文件。 例如,如果您想将自定义单元格设置为视图控制器的属性,则可以这样说:
#import <UIKit/UIKit.h> @class MyCell; @interface RootViewController : UIViewController @property (nonatomic, strong) MyCell *cell; @end
然后,在你的实现文件中,你会实际导入MyCell.h。 提供@class前向声明只是让你不必在头文件中导入关于MyCell类的所有细节。 头文件不需要知道MyCell的所有属性和方法,只是你打算在实现文件中使用它。 所以你@class在头文件中,#import在执行。
在RootViewController.h中:
@interface RootViewController : UITableViewController <UITableViewDelegate>
在RootViewController.m中:
- (void) refreshVisibleViewForCellTagged:(NSInteger)cellTag { NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; MyCell *selectedCell = (MyCell*)[self.myTableView cellForRowAtIndexPath:indexPath]; // nil
等等…
我没有在您的RootViewController
看到RootViewController
声明。 但是如果你的RootViewController
实现了UITableViewController
,你可以使用self.tableView
来访问tableview。 你不需要自己保留一个引用。
@RachelD,如果你的RootView
比UITableViewController
更复杂,可以考虑使用一个单独的类,比如RootTableViewController
。 然后在你的RootView
xib中,为RootTableViewController
创buildIBOutlet
来引用它。 喜欢这个:
// RootTableViewController definition @interface RootTableViewController : UITableViewController { } // RootViewController definition @interface RootViewController : UIViewController { RootTableViewController *table_c; } @property (nonatomic, retain) IBOutlet RootTableViewController *table_c;
请注意,您需要将“对象”拖放到界面生成器中的“对象”部分(对于RootViewController),并在此对象的“自定义类”部分中键入RootTableViewController
。 右键单击这个对象,确保它的IBOutlet,view,2代表被正确设置。
你的myTableView
为零的原因是因为它没有正确初始化。 我的意思是,如果你不使用UITableViewController
你负责通过接口生成器或手动分配它。