UIVIew 子类对象在选项卡栏应用程序中神秘地变为 nil
Hola caballeros,我很困惑,很困惑,更糟糕的是,受阻:在我的第一个选项卡栏项目中,我有一个对象,它是 UIView 的子类“BarGraph”的实例,我之前使用过它,没有遇到任何问题。在这个项目中,我这样做第二个 viewController、graphViewController 的 viewDidLoad 方法中的 alloc-init 设置了 BarGraph,
当我使用选项卡转到不同的 viewControler 时,就会出现问题 。添加到数据中,AOK,但是当我回到另一个选项卡时,BarGraph 显示的数据与之前相同。 NULL:
NSLog(@"barGraph:%@", barGraph)
给出“null”。我只看到这个对象的一个分配初始化,并且我用 NSLog 跟踪了这些。太奇怪了,我正在等待您的建议
。 strong>
这是我的界面:
@interface GraphViewController : UIViewController {
BarGraph *barGraph;
int foo;
}
@property (nonatomic, retain) BarGraph *barGraph;
@property (assign) int foo;
- (void) updateDisplay;
@end
* 来自 epsilon2.7 又名 Jim Carlson: * 下面是我在 GraphViewController.m 中实例化 BarGraph 的地方。我添加了一行“foo = 100;”查看问题是否与所有 ivars 有关或仅与 barGraph 有关。唉,当按 Tab 键离开然后再按 Tab 键返回时, foo 和 barGraph 都会“忘记”它们的值。我非常感谢您的反馈(以及对新手的善意)。
@implementation GraphViewController
@synthesize barGraph, foo;
- (XTabAppDelegate *) theDelegate {
return (XTabAppDelegate *) [UIApplication sharedApplication].delegate;
}
....
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"BARGRAPH: alloc-init");
barGraph = [[BarGraph alloc] initWithFrame:CGRectMake(15, 118, 289, 110)];
foo = 100;
[self.view addSubview:barGraph];
[self updateDisplay];
}
....
@end
应用程序委托的接口,其中存储图表数据:
@interface XTabAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
LogViewController *logViewController; // good
GraphViewController *graphViewController; // bad
Log *currentLog; // data stored here
}
...
@end
currentLog
中的数据持续存在(NSLog
在 GraphViewController 中确认了这一点),我使用以下代码将该数据推送到 barGraph 中在 GraphViewController 中:
-(void) updateBarGraphForDay {
Log *theLog = [self theDelegate].currentLog;
barGraph.data = theLog.log; // main data stored in the theLog.log
foo += 1;
}
根据 ughoavgfhw 的评论,我检查了 graphViewController 和 BarGraph 的 dealloc,例如通过插入 NSLog 语句:
- (void)dealloc {
NSLog(@"deallocating GraphViewController");
[barGraph dealloc];
[super dealloc];
}
两者都没有被调用!
我从来没有看到释放。
(2) 下面是didSelectViewController
的代码。将其
xtabBarController.delegate = self;
作为委托的 didFinishLaunchingWithOptions
方法主体的第一行后,将执行方法 didSelectViewController
(下面的代码)。如果 [graphViewController updateDisplay]
未注释掉,则 (a) 我检测到一个 nil barGraph 对象,(b) 我没有看到显示的新数据(可能是因为相关消息发送到一个 nil 对象) ),(c)如果我通过按下按钮在 graphViewController
中手动执行 [graphViewController updateDisplay]
,则会显示更新的信息。
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(@"UITabBarControllerDelegate method called");
if (viewController == [tabBarController.viewControllers objectAtIndex:1]) {
NSLog(@"graphViewController selected, graphViewControler = %@", graphViewController);
[graphViewController updateDisplay];
}
... + similar if statements
}
当 graphViewController
未初始化时,可能是 [graphViewController updateDisplay]
被调用得太早(???)。我尝试通过在 graphViewController
中实现 viewWillAppear
来规避这些困难。但是,NSLog
告诉我 viewWillAppear
从未被调用。以下是 viewWillAppear
的代码:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:TRUE];
NSLog(@"bb:graphViewController, viewWillAppear called");
[self updateDisplay];
}
Hola caballeros, I am stumped, mystified, and worse yet, stymied: in my first tab bar project I have an object that is instance of a subclass "BarGraph of UIView, which I've used before without trouble. In this project I do an alloc-init in the viewDidLoad method of the second viewController, graphViewController. This sets up the BarGraph. The data which is read in is displayed properly by that object.
The trouble comes when I use a tab to go to a different viewControler where I add to the data. I see the change in the appropriate mutable array. AOK. But when I come back to the other tab, the data displayed by BarGraph is the same as before. After some checking, I found that the BarGraph object had become NULL:
NSLog(@"barGraph:%@", barGraph)
gives "null". All my attempts to fix fail. I see only one alloc-init for this object and no deallocs. These I tracked with NSLog's. Too weird. I await your advice.
Edited to add
Here is my interface:
@interface GraphViewController : UIViewController {
BarGraph *barGraph;
int foo;
}
@property (nonatomic, retain) BarGraph *barGraph;
@property (assign) int foo;
- (void) updateDisplay;
@end
* from epsilon2.7 aka Jim Carlson:
* Below is where I instantiate BarGraph in GraphViewController.m. I added one line "foo = 100;" to see if the problem has to do with all ivars or just barGraph. Alas, both foo and barGraph "forget" their values when tabbing away and then tabbing back. I very much appreciate the feedback (and the kindness to a newb).
@implementation GraphViewController
@synthesize barGraph, foo;
- (XTabAppDelegate *) theDelegate {
return (XTabAppDelegate *) [UIApplication sharedApplication].delegate;
}
....
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"BARGRAPH: alloc-init");
barGraph = [[BarGraph alloc] initWithFrame:CGRectMake(15, 118, 289, 110)];
foo = 100;
[self.view addSubview:barGraph];
[self updateDisplay];
}
....
@end
Interface for app delegate, where the data graphed is stored:
@interface XTabAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
LogViewController *logViewController; // good
GraphViewController *graphViewController; // bad
Log *currentLog; // data stored here
}
...
@end
The data in currentLog
persists (NSLog
confirms this in GraphViewController), and I push that data into barGraph with the following code in GraphViewController:
-(void) updateBarGraphForDay {
Log *theLog = [self theDelegate].currentLog;
barGraph.data = theLog.log; // main data stored in the theLog.log
foo += 1;
}
Following up ughoavgfhw's comment, I checked dealloc for both graphViewController and BarGraph, e.g. by inserting an NSLog statement:
- (void)dealloc {
NSLog(@"deallocating GraphViewController");
[barGraph dealloc];
[super dealloc];
}
Neither is called!
I never see the dealloc.
(2) Below is the code for didSelectViewController
. With
xtabBarController.delegate = self;
in place as the first line of the body of the delegate's didFinishLaunchingWithOptions
method, the method didSelectViewController
(code below) is executed. If [graphViewController updateDisplay]
is not commented out, then (a) I detect a nil barGraph object, (b) I do not see the new data displayed (probably since the relevant message went to a nil object), (c) if I execute [graphViewController updateDisplay]
manually in graphViewController
by pushing a button, then the updated info is displayed.
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(@"UITabBarControllerDelegate method called");
if (viewController == [tabBarController.viewControllers objectAtIndex:1]) {
NSLog(@"graphViewController selected, graphViewControler = %@", graphViewController);
[graphViewController updateDisplay];
}
... + similar if statements
}
It may be that [graphViewController updateDisplay]
is called too early, when graphViewController
is not initialized (???). I've tried to circumvent these difficulties by implementing viewWillAppear
in graphViewController
. However, NSLog
informs me that viewWillAppear
is never called. Here is the code for viewWillAppear
:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:TRUE];
NSLog(@"bb:graphViewController, viewWillAppear called");
[self updateDisplay];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
没什么可继续的,所以在这里在黑暗中拍摄。但是,如果一个对象被释放,指向该对象的指针不会被清空。只有明确设置后,它们才会被取消。此外,您看到旧图表的事实表明该对象存在于内存中的某个位置。
所以,我猜测您将此指针存储在某个类中,例如 A。您有一个由变量 x 指向的类 A 的实例。您的条形图存储在 x 中。从一个选项卡移动到另一个选项卡的过程中的某个时刻。变量 x 使用 A 的新实例重新初始化。这个新实例的 barGraph 尚未初始化,因此为 null。然而,A 的旧实例仍然存在于某处,并且指向 barGraph 的指针仍然完好无损。
Not a lot to go on, so shot in the dark here. But, if an object gets released, pointers to that object are not nulled out. They will only be nulled out if they are explicitly set so. Further, the fact that you are seeing the old graph indicates to me that the object exists in memory some where.
So, I would guess that you are storing this pointer in some class, for example A. You have an instance of the class A pointed to by a variable x. Your barGraph is stored in x. At some point in the process of moving from one tab to another. The variable x is reinitialized with a new instance of A. This new instance hasn't had it's barGraph initialized yet, so is null. However, the old instance of A still exists somewhere and still has its pointer to barGraph intact.
另一个近乎完全的黑暗尝试:您的 BarGraph 对象是一个合成属性,但在该 viewController 中您不小心引用了 iVar (
barGraph =
) 而不是属性 (self.barGraph =
),所以它在该 viewController 中看起来是正确的,但您正在记录该属性,该属性仍然为零。Another nearly-complete stab in the dark: your BarGraph object is a synthesized property but within that viewController you're accidentally referring to the iVar (
barGraph =
) instead of the property (self.barGraph =
) so it looks right in that viewController but you're logging the property, which is still nil.您的问题是,当您更改选项卡时,GraphViewController 正在被释放并重新加载。当视图控制器不被使用时,它被释放。然后,当再次需要时,会创建一个新的。任何持久信息都应存储在由控制器对象访问的模型对象中。这是基本的模型-视图-控制器编程。创建 GraphViewController 时,它应该连接到模型对象并从中加载其信息,而不是尝试存储它本身。
Your problem is that the GraphViewController is being released and reloaded when you change tabs. When a view controller is not being used, it is released. Then, when it is needed again, a new one is created. Any persistent information should be stored in a model object which is accessed by the controller object. This is basic model-view-controller programming. When your GraphViewController is created, it should connect to a model object and load its information from that, instead of trying to store it itself.