UIVIew subclass object becomes mysteriously nil in tabbar app

喜欢而已 提交于 2020-01-06 05:33:44

问题


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];
}

回答1:


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.




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/4456250/uiview-subclass-object-becomes-mysteriously-nil-in-tabbar-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!