简体   繁体   中英

Method in View Controller Called before View initialized - iPhone iOS 5 SDK

For some reason the custom setter of a property never gets called. So it is always coming through as nil at runtime.

I have a view controller that creates an NSArray of NSValue objects and passes it to the view as a property. However, the property always comes through as nil, even when I verify using the debugger that the NSArray in the view controller is just fine.

View Controller @interface GraphingViewController() @property (nonatomic, weak) IBOutlet GraphingView *graphingView; @end

- (void) determinePointsOnGraph
{
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    NSMutableArray *pointsForGraph = [[NSMutableArray alloc] init];

    float startingPoint = -250;
    for (int i = 0; i < 500; i++) {
        float x = startingPoint;
        startingPoint++;

       [dict setValue:[NSNumber numberWithFloat:x] forKey:[NSString stringWithString:@"x"]];
       float y = [CalculatorBrain runProgram:[self graph] usingVariableValues:dict];

       [pointsForGraph addObject:[NSValue valueWithCGPoint:CGPointMake(x,y)]];
}

//This calls the pointer to the view, and the setter for the view's property
[self.graphingView setPointsOnGraph:pointsForGraph];
}

View

@synthesize pointsOnGraph = _pointsOnGraph;
- (void)setPointsOnGraph:(NSArray *)pointsOnGraph
{
    //Custom setter for property, never gets called if a break point is put here
    _pointsOnGraph = pointsOnGraph;
    [self setNeedsDisplay];
}

- (void)drawLine:(NSArray *)pointsOfLine inContext:(CGContextRef)context
{    
    CGPoint pointsOfLineAsCGPoints[[pointsOfLine count]];

    for (int i = 0; i < sizeof(pointsOfLineAsCGPoints); i++) {
       pointsOfLineAsCGPoints[i] = [[pointsOfLine objectAtIndex:i] CGPointValue];
    }

    CGContextAddLines(context, pointsOfLineAsCGPoints, sizeof(pointsOfLine));
    CGContextClosePath(context);
    CGContextStrokePath(context);
}

The drawLine method is called by the drawRect and is passed the pointsOnGraph property as pointsOfLine. Even if I put a break point in the drawRect and look at the pointsOnGraph property it's always nil in the view. However, when it is passed to the view by the view controller it contains hundreds of objects.

I just don't understand why the property is always nil, and if I put a break point in the setter it never gets called.

Update I have verified that the faceView reference to the view is nil when it is first called, but the IBOutlet appears to be hooked up properly, and the view eventually gets display. It seems that the view controller method is getting called before the self.graphingView IBOutlet is initialized

The Following is from the View Controller that I segue from

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([segue.identifier isEqualToString:@"Graphing"] ) {
        [segue.destinationViewController setGraph:[[self.brain program] mutableCopy]]; 
        [segue.destinationViewController determinePointsOnGraph];

    }
}

Solution Call the determinePointsOnGraph method in the viewDidLoad delegate rather than in prepare for segue. This ensures that the view has been created. I also had another problem stemming from the fact that the outlet from the view to access the data in the view controller wasn't initialized in the view setter.

调用setter之前,请确保self.graphingView不为nil

在视图委托方法viewDidLoad中调用图上的确定点

It seems like you are sending the message - (void)setPointsOnGraph:(NSArray *)pointsOnGraph too early before the self.graphingView gets initialized.

I would suggest that you send the message - (void) determinePointsOnGraph in viewWillAppear of the GraphingViewController. This is because your self.graphingView should be initialized (which should be done by the time -viewDidLoad gets called) before you set the NSArray pointsOnGraph.

To confirm that my suggestion would work, please add your implementation of this GraphingViewController, especially the portion that calls the message - (void) determinePointsOnGraph .

For your reference, when I get confused with views and the sequence of the methods, I input NSLogs in viewDidAppear, viewDidLoad, drawRect, and viewWillAppear to clarify what is happening. The sequence should be viewDidLoad -> viewWillAppear -> drawRect -> viewDidAppear .

On another point, if your code works properly, your setter method in the graphingView will leak memory. You need to release your _pointsOnGraph before you set it to the given pointer. For example, you could implement it as follows:

- (void)setPointsOnGraph:(NSArray *)pointsOnGraph
{
    [_pointsOnGraph release];
    _pointsOnGraph = pointsOnGraph;
    [self setNeedsDisplay];
}

plus, you should autorelease the NSArray before you send it with the message, for example:

[self.graphingView setPointsOnGraph:[pointsForGraph autorelease]];

but better yet, you can reduce the amount of code and brackets by not alloc init'ing the NSMutableArray. This can be done by changing

NSMutableArray *pointsForGraph = [[NSMutableArray alloc] init];

to

NSMutableArray *pointsForGraph = [NSMutableArray dictionary];

and forget about the autorelease.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM